diff --git a/src/client.hpp b/src/client.hpp
index ec3dbbc7f3b1999bb43843c84473a315c04fd8a1..73ede1c948d51f026080b5e9e2d2a5e642b47f42 100644
--- a/src/client.hpp
+++ b/src/client.hpp
@@ -288,6 +288,9 @@ mtx::client::Client::post(const std::string &endpoint,
         std::shared_ptr<Session> session = create_session<Response>(
           [callback](const Response &res, HeaderFields, RequestErr err) { callback(res, err); });
 
+        if (!session)
+                return;
+
         setup_auth(session, requires_auth);
 
         session->request.method(boost::beast::http::verb::post);
@@ -312,6 +315,9 @@ mtx::client::Client::put(const std::string &endpoint,
         std::shared_ptr<Session> session = create_session<Response>(
           [callback](const Response &res, HeaderFields, RequestErr err) { callback(res, err); });
 
+        if (!session)
+                return;
+
         setup_auth(session, requires_auth);
 
         session->request.method(boost::beast::http::verb::put);
@@ -348,6 +354,9 @@ mtx::client::Client::get(const std::string &endpoint,
 {
         std::shared_ptr<Session> session = create_session<Response>(callback);
 
+        if (!session)
+                return;
+
         setup_auth(session, requires_auth);
 
         session->request.method(boost::beast::http::verb::get);
@@ -384,9 +393,7 @@ mtx::client::Client::create_session(
                                   return callback(response_data, response.base(), client_error);
                           }
 
-                          // TODO: handle http error.
                           if (response.result() != boost::beast::http::status::ok) {
-                                  // TODO: handle unknown error.
                                   client_error.status_code = response.result();
 
                                   try {
@@ -396,19 +403,21 @@ mtx::client::Client::create_session(
                                           client_error.matrix_error = matrix_error;
                                           return callback(
                                             response_data, response.base(), client_error);
-                                  } catch (nlohmann::json::exception &e) {
-                                          std::cout << e.what() << ": Couldn't parse response\n"
-                                                    << response.body() << std::endl;
-                                          // TODO: handle error
+                                  } catch (const nlohmann::json::exception &e) {
+                                          client_error.parse_error =
+                                            std::string(e.what()) + ": " + response.body();
+
+                                          return callback(
+                                            response_data, response.base(), client_error);
                                   }
                           }
 
                           try {
                                   response_data = deserialize<Response>(response.body());
-                          } catch (nlohmann::json::exception &e) {
-                                  std::cout << e.what() << ": Couldn't parse response\n"
-                                            << response.body() << std::endl;
-                                  // TODO: handle error
+                          } catch (const nlohmann::json::exception &e) {
+                                  client_error.parse_error =
+                                    std::string(e.what()) + ": " + response.body();
+                                  return callback(response_data, response.base(), client_error);
                           }
 
                           callback(response_data, response.base(), {});
@@ -424,12 +433,20 @@ mtx::client::Client::create_session(
           });
 
         // Set SNI Hostname (many hosts need this to handshake successfully)
-        // TODO: handle the error
         if (!SSL_set_tlsext_host_name(session->socket.native_handle(), server_.c_str())) {
                 boost::system::error_code ec{static_cast<int>(::ERR_get_error()),
                                              boost::asio::error::get_ssl_category()};
                 std::cerr << ec.message() << "\n";
-                return session;
+
+                Response response_data;
+
+                mtx::client::errors::ClientError client_error;
+                client_error.error_code = ec;
+
+                callback(response_data, {}, client_error);
+
+                // Initialization failed.
+                return nullptr;
         }
 
         return session;
diff --git a/src/errors.hpp b/src/errors.hpp
index 393dfd5050e3c2802624fa6c89704a27df7f8ba8..4a85fba086363f8fde10f57a61f605718533a104 100644
--- a/src/errors.hpp
+++ b/src/errors.hpp
@@ -16,6 +16,8 @@ struct ClientError
         boost::system::error_code error_code;
         //! Status code of the associated http response.
         boost::beast::http::status status_code;
+        //! Parsing response error.
+        std::string parse_error;
 };
 }
 }
diff --git a/tests/client_api.cpp b/tests/client_api.cpp
index 79415780d08da197c9bc4b99ba16f40abf422839..90676884b2394c31de93774a6d7f071689283672 100644
--- a/tests/client_api.cpp
+++ b/tests/client_api.cpp
@@ -27,6 +27,9 @@ check_error(ErrType err)
                      << "\n";
                 cout << "error_code      : " << err->error_code << "\n";
                 cout << "status_code     : " << err->status_code << "\n";
+
+                if (!err->parse_error.empty())
+                        cout << "parse_error     : " << err->parse_error << "\n";
         }
 
         ASSERT_FALSE(err);