diff --git a/include/mtxclient/crypto/client.hpp b/include/mtxclient/crypto/client.hpp
index 3813f1f6c19cf9917c6157be4d8148cd5d66c709..fb7ede0dd6113bc753de7ac5f012ce8a3316332e 100644
--- a/include/mtxclient/crypto/client.hpp
+++ b/include/mtxclient/crypto/client.hpp
@@ -31,51 +31,79 @@ namespace crypto {
 //! Data representation used to interact with libolm.
 using BinaryBuf = std::vector<uint8_t>;
 
+enum class OlmErrorCode {
+	UNKNOWN_ERROR = - 1,
+	SUCCESS,
+	NOT_ENOUGH_RANDOM,
+	OUTPUT_BUFFER_TOO_SMALL,
+	BAD_MESSAGE_VERSION,
+	BAD_MESSAGE_FORMAT,
+	BAD_MESSAGE_MAC,
+	BAD_MESSAGE_KEY_ID,
+	INVALID_BASE64,
+	BAD_ACCOUNT_KEY,
+	UNKNOWN_PICKLE_VERSION,
+	CORRUPTED_PICKLE,
+	BAD_SESSION_KEY,
+	UNKNOWN_MESSAGE_INDEX,
+	BAD_LEGACY_ACCOUNT_PICKLE,
+	BAD_SIGNATURE,
+	OLM_INPUT_BUFFER_TOO_SMALL,
+	OLM_SAS_THEIR_KEY_NOT_SET
+};
+
 //! Errors returned by the olm library
 class olm_exception : public std::exception
 {
-public:
-        olm_exception(std::string func, OlmSession *s)
-          : msg_(func + ": " + std::string(olm_session_last_error(s)))
-        {}
+	public:
+		olm_exception(std::string func, OlmSession *s)
+			: olm_exception(std::move(func), std::string(olm_session_last_error(s)))
+		{}
 
-        olm_exception(std::string func, OlmAccount *acc)
-          : msg_(func + ": " + std::string(olm_account_last_error(acc)))
-        {}
+		olm_exception(std::string func, OlmAccount *acc)
+			: olm_exception(std::move(func), std::string(olm_account_last_error(acc)))
+		{}
 
-        olm_exception(std::string func, OlmUtility *util)
-          : msg_(func + ": " + std::string(olm_utility_last_error(util)))
-        {}
+		olm_exception(std::string func, OlmUtility *util)
+			: olm_exception(std::move(func), std::string(olm_utility_last_error(util)))
+		{}
 
-        olm_exception(std::string func, OlmPkDecryption *s)
-          : msg_(func + ": " + std::string(olm_pk_decryption_last_error(s)))
-        {}
+		olm_exception(std::string func, OlmPkDecryption *s)
+			: olm_exception(std::move(func), std::string(olm_pk_decryption_last_error(s)))
+		{}
 
-        olm_exception(std::string func, OlmPkSigning *s)
-          : msg_(func + ": " + std::string(olm_pk_signing_last_error(s)))
-        {}
+		olm_exception(std::string func, OlmPkSigning *s)
+			: olm_exception(std::move(func), std::string(olm_pk_signing_last_error(s)))
+		{}
 
-        olm_exception(std::string func, OlmOutboundGroupSession *s)
-          : msg_(func + ": " + std::string(olm_outbound_group_session_last_error(s)))
-        {}
+		olm_exception(std::string func, OlmOutboundGroupSession *s)
+			: olm_exception(std::move(func), std::string(olm_outbound_group_session_last_error(s)))
+		{}
 
-        olm_exception(std::string func, OlmInboundGroupSession *s)
-          : msg_(func + ": " + std::string(olm_inbound_group_session_last_error(s)))
-        {}
+		olm_exception(std::string func, OlmInboundGroupSession *s)
+			: olm_exception(std::move(func), std::string(olm_inbound_group_session_last_error(s)))
+		{}
 
-        olm_exception(std::string func, OlmSAS *s)
-          : msg_(func + ":" + std::string(olm_sas_last_error(s)))
-        {}
+		olm_exception(std::string func, OlmSAS *s)
+			: olm_exception(std::move(func), std::string(olm_sas_last_error(s)))
+		{}
 
-        olm_exception(std::string msg)
-          : msg_(msg)
-        {}
+                //! Returns a description of the olm error.
+                const char *what() const noexcept override { return msg_.c_str(); }
 
-        //! Returns a description of the olm error.
-        const char *what() const noexcept override { return msg_.c_str(); }
+                //! Returns an error code reconstructed from the error string returned by olm
+                OlmErrorCode error_code() const noexcept { return ec_; }
+
+        private:
+                olm_exception(std::string &&func, std::string error_string)
+                  : msg_(func + ": " + error_string)
+                  , ec_(ec_from_string(error_string))
+                {}
+
+		OlmErrorCode ec_from_string(std::string_view);
 
-private:
         std::string msg_;
+	OlmErrorCode ec_ = OlmErrorCode::UNKNOWN_ERROR;
 };
 
 //! Serialize olm objects into strings encrypted using key to persist them on non volatile storage.
diff --git a/lib/crypto/client.cpp b/lib/crypto/client.cpp
index feb8574d98a2c54ab3aa3583b8ce273fe1a617c4..73e3ea78d7b022b5b387ff066a048d1ad342a849 100644
--- a/lib/crypto/client.cpp
+++ b/lib/crypto/client.cpp
@@ -14,6 +14,40 @@ using namespace mtx::crypto;
 
 static constexpr auto pwhash_SALTBYTES = 16u;
 
+using namespace std::string_view_literals;
+
+static const std::array olmErrorStrings{
+  "SUCCESS"sv,
+  "NOT_ENOUGH_RANDOM"sv,
+  "OUTPUT_BUFFER_TOO_SMALL"sv,
+  "BAD_MESSAGE_VERSION"sv,
+  "BAD_MESSAGE_FORMAT"sv,
+  "BAD_MESSAGE_MAC"sv,
+  "BAD_MESSAGE_KEY_ID"sv,
+  "INVALID_BASE64"sv,
+  "BAD_ACCOUNT_KEY"sv,
+  "UNKNOWN_PICKLE_VERSION"sv,
+  "CORRUPTED_PICKLE"sv,
+  "BAD_SESSION_KEY"sv,
+  "UNKNOWN_MESSAGE_INDEX"sv,
+  "BAD_LEGACY_ACCOUNT_PICKLE"sv,
+  "BAD_SIGNATURE"sv,
+  "OLM_INPUT_BUFFER_TOO_SMALL"sv,
+  "OLM_SAS_THEIR_KEY_NOT_SET"sv,
+
+};
+
+OlmErrorCode
+olm_exception::ec_from_string(std::string_view error)
+{
+        for (size_t i = 0; i < olmErrorStrings.size(); i++) {
+                if (olmErrorStrings[i] == error)
+                        return static_cast<OlmErrorCode>(i);
+        }
+
+        return OlmErrorCode::UNKNOWN_ERROR;
+}
+
 void
 OlmClient::create_new_account()
 {