diff --git a/tests/client_api.cpp b/tests/client_api.cpp
index 50e74aac28d10a747e55fe87dcb02c10c2fef994..3921febe8b51965455cb31a55a7e02f4626a4c82 100644
--- a/tests/client_api.cpp
+++ b/tests/client_api.cpp
@@ -17,6 +17,20 @@ using namespace std;
 
 using ErrType = std::experimental::optional<errors::ClientError>;
 
+void
+check_error(ErrType err)
+{
+        if (err) {
+                cout << "matrix (error)  : " << err->matrix_error.error << "\n";
+                cout << "matrix (errcode): " << mtx::errors::to_string(err->matrix_error.errcode)
+                     << "\n";
+                cout << "error_code      : " << err->error_code << "\n";
+                cout << "status_code     : " << err->status_code << "\n";
+        }
+
+        ASSERT_FALSE(err);
+}
+
 void
 validate_login(const std::string &user, const mtx::responses::Login &res)
 {
@@ -42,17 +56,17 @@ TEST(ClientAPI, LoginSuccess)
         std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost");
 
         mtx_client->login("alice", "secret", [](const mtx::responses::Login &res, ErrType err) {
-                ASSERT_FALSE(err);
+                check_error(err);
                 validate_login("@alice:localhost", res);
         });
 
         mtx_client->login("bob", "secret", [](const mtx::responses::Login &res, ErrType err) {
-                ASSERT_FALSE(err);
+                check_error(err);
                 validate_login("@bob:localhost", res);
         });
 
         mtx_client->login("carl", "secret", [](const mtx::responses::Login &res, ErrType err) {
-                ASSERT_FALSE(err);
+                check_error(err);
                 validate_login("@carl:localhost", res);
         });
 
@@ -101,14 +115,12 @@ TEST(ClientAPI, ChangeDisplayName)
         std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost");
 
         mtx_client->login(
-          "alice", "secret", [mtx_client](const mtx::responses::Login &res, ErrType err) {
-                  ASSERT_FALSE(err);
-                  validate_login("@alice:localhost", res);
+          "alice", "secret", [mtx_client](const mtx::responses::Login &, ErrType err) {
+                  check_error(err);
 
                   // Change the display name to Arthur Dent and verify its success through the lack
                   // of an error
-                  mtx_client->set_displayname("Arthur Dent",
-                                              [](ErrType err) { ASSERT_FALSE(err); });
+                  mtx_client->set_displayname("Arthur Dent", [](ErrType err) { check_error(err); });
           });
 
         mtx_client->close();
@@ -119,13 +131,12 @@ TEST(ClientAPI, EmptyDisplayName)
         std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost");
 
         mtx_client->login(
-          "alice", "secret", [mtx_client](const mtx::responses::Login &res, ErrType err) {
-                  ASSERT_FALSE(err);
-                  validate_login("@alice:localhost", res);
+          "alice", "secret", [mtx_client](const mtx::responses::Login &, ErrType err) {
+                  check_error(err);
 
                   // Change the display name to an empty string and verify its success through the
                   // lack of an error
-                  mtx_client->set_displayname("", [](ErrType err) { ASSERT_FALSE(err); });
+                  mtx_client->set_displayname("", [](ErrType err) { check_error(err); });
           });
 
         mtx_client->close();
@@ -136,9 +147,8 @@ TEST(ClientAPI, CreateRoom)
         std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost");
 
         mtx_client->login(
-          "alice", "secret", [mtx_client](const mtx::responses::Login &res, ErrType err) {
-                  ASSERT_FALSE(err);
-                  validate_login("@alice:localhost", res);
+          "alice", "secret", [mtx_client](const mtx::responses::Login &, ErrType err) {
+                  check_error(err);
           });
 
         // Waiting for the previous request to complete.
@@ -148,7 +158,7 @@ TEST(ClientAPI, CreateRoom)
         req.name  = "Name";
         req.topic = "Topic";
         mtx_client->create_room(req, [](const mtx::responses::CreateRoom &res, ErrType err) {
-                ASSERT_FALSE(err);
+                check_error(err);
                 ASSERT_TRUE(res.room_id.localpart().size() > 10);
                 EXPECT_EQ(res.room_id.hostname(), "localhost");
         });
@@ -164,8 +174,7 @@ TEST(ClientAPI, LogoutSuccess)
         // Login and prove that login was successful by creating a room
         mtx_client->login(
           "alice", "secret", [&token](const mtx::responses::Login &res, ErrType err) {
-                  ASSERT_FALSE(err);
-                  validate_login("@alice:localhost", res);
+                  check_error(err);
                   token = res.access_token;
           });
         while (token.empty()) {
@@ -176,15 +185,12 @@ TEST(ClientAPI, LogoutSuccess)
         mtx::requests::CreateRoom req;
         req.name  = "Test1";
         req.topic = "Topic1";
-        mtx_client->create_room(req, [](const mtx::responses::CreateRoom &res, ErrType err) {
-                boost::ignore_unused(res);
-                ASSERT_FALSE(err);
-        });
+        mtx_client->create_room(
+          req, [](const mtx::responses::CreateRoom &, ErrType err) { check_error(err); });
 
         // Logout and prove that logout was successful and deleted the access_token_ for the client
-        mtx_client->logout([mtx_client, &token](const mtx::responses::Logout &res, ErrType err) {
-                boost::ignore_unused(res);
-                ASSERT_FALSE(err);
+        mtx_client->logout([mtx_client, &token](const mtx::responses::Logout &, ErrType err) {
+                check_error(err);
                 token.clear();
         });
         while (token.size()) {
@@ -195,8 +201,7 @@ TEST(ClientAPI, LogoutSuccess)
         mtx::requests::CreateRoom failReq;
         failReq.name  = "42";
         failReq.topic = "LifeUniverseEverything";
-        mtx_client->create_room(failReq, [](const mtx::responses::CreateRoom &res, ErrType err) {
-                boost::ignore_unused(res);
+        mtx_client->create_room(failReq, [](const mtx::responses::CreateRoom &, ErrType err) {
                 ASSERT_TRUE(err);
                 EXPECT_EQ(mtx::errors::to_string(err->matrix_error.errcode), "M_MISSING_TOKEN");
                 EXPECT_EQ(err->status_code, boost::beast::http::status::forbidden);
@@ -214,8 +219,7 @@ TEST(ClientAPI, LogoutInvalidatesTokenOnServer)
         // Login and prove that login was successful by creating a room
         mtx_client->login(
           "alice", "secret", [&token](const mtx::responses::Login &res, ErrType err) {
-                  ASSERT_FALSE(err);
-                  validate_login("@alice:localhost", res);
+                  check_error(err);
                   token = res.access_token;
           });
         while (token.empty()) {
@@ -226,16 +230,13 @@ TEST(ClientAPI, LogoutInvalidatesTokenOnServer)
         mtx::requests::CreateRoom req;
         req.name  = "Test1";
         req.topic = "Topic1";
-        mtx_client->create_room(req, [](const mtx::responses::CreateRoom &res, ErrType err) {
-                boost::ignore_unused(res);
-                ASSERT_FALSE(err);
-        });
+        mtx_client->create_room(
+          req, [](const mtx::responses::CreateRoom &, ErrType err) { check_error(err); });
 
         // Logout and prove that logout was successful by verifying the old access_token_ is no
         // longer valid
-        mtx_client->logout([mtx_client, &token](const mtx::responses::Logout &res, ErrType err) {
-                boost::ignore_unused(res);
-                ASSERT_FALSE(err);
+        mtx_client->logout([mtx_client, &token](const mtx::responses::Logout &, ErrType err) {
+                check_error(err);
                 mtx_client->set_access_token(token);
                 token.clear();
         });
@@ -247,8 +248,7 @@ TEST(ClientAPI, LogoutInvalidatesTokenOnServer)
         mtx::requests::CreateRoom failReq;
         failReq.name  = "42";
         failReq.topic = "LifeUniverseEverything";
-        mtx_client->create_room(failReq, [](const mtx::responses::CreateRoom &res, ErrType err) {
-                boost::ignore_unused(res);
+        mtx_client->create_room(failReq, [](const mtx::responses::CreateRoom &, ErrType err) {
                 ASSERT_TRUE(err);
                 EXPECT_EQ(mtx::errors::to_string(err->matrix_error.errcode), "M_UNKNOWN_TOKEN");
                 EXPECT_EQ(err->status_code, boost::beast::http::status::forbidden);
@@ -263,19 +263,15 @@ TEST(ClientAPI, CreateRoomInvites)
         auto bob   = std::make_shared<Client>("localhost");
         auto carl  = std::make_shared<Client>("localhost");
 
-        alice->login("alice", "secret", [alice](const mtx::responses::Login &res, ErrType err) {
-                boost::ignore_unused(res);
-                ASSERT_FALSE(err);
+        alice->login("alice", "secret", [alice](const mtx::responses::Login &, ErrType err) {
+                check_error(err);
         });
 
-        bob->login("bob", "secret", [bob](const mtx::responses::Login &res, ErrType err) {
-                boost::ignore_unused(res);
-                ASSERT_FALSE(err);
-        });
+        bob->login(
+          "bob", "secret", [bob](const mtx::responses::Login &, ErrType err) { check_error(err); });
 
-        carl->login("carl", "secret", [carl](const mtx::responses::Login &res, ErrType err) {
-                boost::ignore_unused(res);
-                ASSERT_FALSE(err);
+        carl->login("carl", "secret", [carl](const mtx::responses::Login &, ErrType err) {
+                check_error(err);
         });
 
         // Waiting for the previous requests to complete.
@@ -286,14 +282,14 @@ TEST(ClientAPI, CreateRoomInvites)
         req.topic  = "Topic";
         req.invite = {"@bob:localhost", "@carl:localhost"};
         alice->create_room(req, [bob, carl](const mtx::responses::CreateRoom &res, ErrType err) {
-                ASSERT_FALSE(err);
+                check_error(err);
                 auto room_id = res.room_id;
 
                 bob->join_room(res.room_id,
-                               [](const nlohmann::json &, ErrType err) { ASSERT_FALSE(err); });
+                               [](const nlohmann::json &, ErrType err) { check_error(err); });
 
                 carl->join_room(res.room_id,
-                                [](const nlohmann::json &, ErrType err) { ASSERT_FALSE(err); });
+                                [](const nlohmann::json &, ErrType err) { check_error(err); });
         });
 
         alice->close();
@@ -306,15 +302,12 @@ TEST(ClientAPI, JoinRoom)
         auto alice = std::make_shared<Client>("localhost");
         auto bob   = std::make_shared<Client>("localhost");
 
-        alice->login("alice", "secret", [alice](const mtx::responses::Login &res, ErrType err) {
-                boost::ignore_unused(res);
-                ASSERT_FALSE(err);
+        alice->login("alice", "secret", [alice](const mtx::responses::Login &, ErrType err) {
+                check_error(err);
         });
 
-        bob->login("bob", "secret", [bob](const mtx::responses::Login &res, ErrType err) {
-                boost::ignore_unused(res);
-                ASSERT_FALSE(err);
-        });
+        bob->login(
+          "bob", "secret", [bob](const mtx::responses::Login &, ErrType err) { check_error(err); });
 
         // Waiting for the previous requests to complete.
         std::this_thread::sleep_for(std::chrono::seconds(3));
@@ -329,11 +322,11 @@ TEST(ClientAPI, JoinRoom)
         req.invite          = {"@bob:localhost"};
         req.room_alias_name = alias;
         alice->create_room(req, [bob, alias](const mtx::responses::CreateRoom &res, ErrType err) {
-                ASSERT_FALSE(err);
+                check_error(err);
                 auto room_id = res.room_id;
 
                 bob->join_room(res.room_id,
-                               [](const nlohmann::json &, ErrType err) { ASSERT_FALSE(err); });
+                               [](const nlohmann::json &, ErrType err) { check_error(err); });
 
                 using namespace mtx::identifiers;
                 bob->join_room(parse<Room>("!random_room_id:localhost"),
@@ -345,7 +338,7 @@ TEST(ClientAPI, JoinRoom)
 
                 // Join the room using an alias.
                 bob->join_room("#" + alias + ":localhost",
-                               [](const nlohmann::json &, ErrType err) { ASSERT_FALSE(err); });
+                               [](const nlohmann::json &, ErrType err) { check_error(err); });
         });
 
         alice->close();
@@ -357,15 +350,12 @@ TEST(ClientAPI, LeaveRoom)
         auto alice = std::make_shared<Client>("localhost");
         auto bob   = std::make_shared<Client>("localhost");
 
-        alice->login("alice", "secret", [alice](const mtx::responses::Login &res, ErrType err) {
-                boost::ignore_unused(res);
-                ASSERT_FALSE(err);
+        alice->login("alice", "secret", [alice](const mtx::responses::Login &, ErrType err) {
+                check_error(err);
         });
 
-        bob->login("bob", "secret", [bob](const mtx::responses::Login &res, ErrType err) {
-                boost::ignore_unused(res);
-                ASSERT_FALSE(err);
-        });
+        bob->login(
+          "bob", "secret", [bob](const mtx::responses::Login &, ErrType err) { check_error(err); });
 
         // Waiting for the previous requests to complete.
         std::this_thread::sleep_for(std::chrono::seconds(3));
@@ -375,14 +365,14 @@ TEST(ClientAPI, LeaveRoom)
         req.topic  = "Topic";
         req.invite = {"@bob:localhost"};
         alice->create_room(req, [bob](const mtx::responses::CreateRoom &res, ErrType err) {
-                ASSERT_FALSE(err);
+                check_error(err);
                 auto room_id = res.room_id;
 
                 bob->join_room(res.room_id, [room_id, bob](const nlohmann::json &, ErrType err) {
-                        ASSERT_FALSE(err);
+                        check_error(err);
 
                         bob->leave_room(
-                          room_id, [](const nlohmann::json &, ErrType err) { ASSERT_FALSE(err); });
+                          room_id, [](const nlohmann::json &, ErrType err) { check_error(err); });
                 });
         });
 
@@ -403,15 +393,12 @@ TEST(ClientAPI, InviteRoom)
         auto alice = std::make_shared<Client>("localhost");
         auto bob   = std::make_shared<Client>("localhost");
 
-        alice->login("alice", "secret", [alice](const mtx::responses::Login &res, ErrType err) {
-                boost::ignore_unused(res);
-                ASSERT_FALSE(err);
+        alice->login("alice", "secret", [alice](const mtx::responses::Login &, ErrType err) {
+                check_error(err);
         });
 
-        bob->login("bob", "secret", [bob](const mtx::responses::Login &res, ErrType err) {
-                boost::ignore_unused(res);
-                ASSERT_FALSE(err);
-        });
+        bob->login(
+          "bob", "secret", [bob](const mtx::responses::Login &, ErrType err) { check_error(err); });
 
         // Waiting for the previous requests to complete.
         std::this_thread::sleep_for(std::chrono::seconds(3));
@@ -421,22 +408,19 @@ TEST(ClientAPI, InviteRoom)
         req.topic  = "Topic";
         req.invite = {};
         alice->create_room(req, [alice, bob](const mtx::responses::CreateRoom &res, ErrType err) {
-                ASSERT_FALSE(err);
+                check_error(err);
                 auto room_id = res.room_id;
 
-                alice->invite_user(
-                  room_id,
-                  "@bob:localhost",
-                  [room_id, bob](const mtx::responses::Empty &, ErrType err) {
-                          ASSERT_FALSE(err);
-                          if (err) {
-                                  std::cout << "Received error when inviting user" << std::endl;
-                          }
-
-                          bob->join_room(room_id, [](const nlohmann::json &, ErrType err) {
-                                  ASSERT_FALSE(err);
-                          });
-                  });
+                alice->invite_user(room_id,
+                                   "@bob:localhost",
+                                   [room_id, bob](const mtx::responses::Empty &, ErrType err) {
+                                           check_error(err);
+
+                                           bob->join_room(room_id,
+                                                          [](const nlohmann::json &, ErrType err) {
+                                                                  check_error(err);
+                                                          });
+                                   });
         });
 
         alice->close();
@@ -448,15 +432,12 @@ TEST(ClientAPI, InvalidInvite)
         auto alice = std::make_shared<Client>("localhost");
         auto bob   = std::make_shared<Client>("localhost");
 
-        alice->login("alice", "secret", [alice](const mtx::responses::Login &res, ErrType err) {
-                boost::ignore_unused(res);
-                ASSERT_FALSE(err);
+        alice->login("alice", "secret", [alice](const mtx::responses::Login &, ErrType err) {
+                check_error(err);
         });
 
-        bob->login("bob", "secret", [bob](const mtx::responses::Login &res, ErrType err) {
-                boost::ignore_unused(res);
-                ASSERT_FALSE(err);
-        });
+        bob->login(
+          "bob", "secret", [bob](const mtx::responses::Login &, ErrType err) { check_error(err); });
 
         // Waiting for the previous requests to complete.
         std::this_thread::sleep_for(std::chrono::seconds(3));
@@ -466,7 +447,7 @@ TEST(ClientAPI, InvalidInvite)
         req.topic  = "Topic";
         req.invite = {};
         alice->create_room(req, [alice, bob](const mtx::responses::CreateRoom &res, ErrType err) {
-                ASSERT_FALSE(err);
+                check_error(err);
                 auto room_id = res.room_id;
 
                 bob->invite_user(room_id,
@@ -489,9 +470,8 @@ TEST(ClientAPI, Sync)
         std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost");
 
         mtx_client->login(
-          "alice", "secret", [mtx_client](const mtx::responses::Login &res, ErrType err) {
-                  boost::ignore_unused(res);
-                  ASSERT_FALSE(err);
+          "alice", "secret", [mtx_client](const mtx::responses::Login &, ErrType err) {
+                  check_error(err);
           });
 
         while (mtx_client->access_token().empty())
@@ -501,11 +481,11 @@ TEST(ClientAPI, Sync)
         req.name  = "Name";
         req.topic = "Topic";
         mtx_client->create_room(req, [mtx_client](const mtx::responses::CreateRoom &, ErrType err) {
-                ASSERT_FALSE(err);
+                check_error(err);
 
                 mtx_client->sync(
                   "", "", false, 0, [](const mtx::responses::Sync &res, ErrType err) {
-                          ASSERT_FALSE(err);
+                          check_error(err);
                           ASSERT_TRUE(res.rooms.join.size() > 0);
                           ASSERT_TRUE(res.next_batch.size() > 0);
                   });
@@ -519,7 +499,7 @@ TEST(ClientAPI, Versions)
         std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost");
 
         mtx_client->versions([](const mtx::responses::Versions &res, ErrType err) {
-                ASSERT_FALSE(err);
+                check_error(err);
 
                 EXPECT_EQ(res.versions.size(), 4);
                 EXPECT_EQ(res.versions.at(0), "r0.0.1");
@@ -536,17 +516,17 @@ TEST(ClientAPI, Typing)
         auto alice = std::make_shared<Client>("localhost");
 
         alice->login(
-          "alice", "secret", [](const mtx::responses::Login &, ErrType err) { ASSERT_FALSE(err); });
+          "alice", "secret", [](const mtx::responses::Login &, ErrType err) { check_error(err); });
 
         while (alice->access_token().empty())
                 std::this_thread::sleep_for(std::chrono::milliseconds(100));
 
         mtx::requests::CreateRoom req;
         alice->create_room(req, [alice](const mtx::responses::CreateRoom &res, ErrType err) {
-                ASSERT_FALSE(err);
+                check_error(err);
 
                 alice->start_typing(res.room_id, 10000, [alice, res](ErrType err) {
-                        ASSERT_FALSE(err);
+                        check_error(err);
 
                         const auto room_id = res.room_id.toString();
                         atomic_bool can_continue(false);
@@ -557,7 +537,7 @@ TEST(ClientAPI, Typing)
                           false,
                           0,
                           [room_id, &can_continue](const mtx::responses::Sync &res, ErrType err) {
-                                  ASSERT_FALSE(err);
+                                  check_error(err);
 
                                   can_continue = true;
 
@@ -571,7 +551,7 @@ TEST(ClientAPI, Typing)
                                 std::this_thread::sleep_for(std::chrono::milliseconds(100));
 
                         alice->stop_typing(res.room_id, [alice, room_id](ErrType err) {
-                                ASSERT_FALSE(err);
+                                check_error(err);
 
                                 alice->sync(
                                   "",
@@ -579,7 +559,7 @@ TEST(ClientAPI, Typing)
                                   false,
                                   0,
                                   [room_id](const mtx::responses::Sync &res, ErrType err) {
-                                          ASSERT_FALSE(err);
+                                          check_error(err);
                                           auto room = res.rooms.join.at(room_id);
                                           EXPECT_EQ(room.ephemeral.typing.size(), 0);
                                   });
@@ -595,15 +575,12 @@ TEST(ClientAPI, SendMessages)
         auto alice = std::make_shared<Client>("localhost");
         auto bob   = std::make_shared<Client>("localhost");
 
-        alice->login("alice", "secret", [alice](const mtx::responses::Login &res, ErrType err) {
-                boost::ignore_unused(res);
-                ASSERT_FALSE(err);
+        alice->login("alice", "secret", [alice](const mtx::responses::Login &, ErrType err) {
+                check_error(err);
         });
 
-        bob->login("bob", "secret", [bob](const mtx::responses::Login &res, ErrType err) {
-                boost::ignore_unused(res);
-                ASSERT_FALSE(err);
-        });
+        bob->login(
+          "bob", "secret", [bob](const mtx::responses::Login &, ErrType err) { check_error(err); });
 
         while (alice->access_token().empty() && bob->access_token().empty())
                 std::this_thread::sleep_for(std::chrono::milliseconds(100));
@@ -611,12 +588,12 @@ TEST(ClientAPI, SendMessages)
         mtx::requests::CreateRoom req;
         req.invite = {"@bob:localhost"};
         alice->create_room(req, [alice, bob](const mtx::responses::CreateRoom &res, ErrType err) {
-                ASSERT_FALSE(err);
+                check_error(err);
                 auto room_id = res.room_id;
 
                 bob->join_room(
                   res.room_id, [alice, bob, room_id](const nlohmann::json &, ErrType err) {
-                          ASSERT_FALSE(err);
+                          check_error(err);
 
                           // Flag to indicate when those messages would be ready to be read by
                           // alice.
@@ -631,7 +608,7 @@ TEST(ClientAPI, SendMessages)
                             text,
                             [&event_ids](const mtx::responses::EventId &res, ErrType err) {
                                     event_ids.push_back(res.event_id.toString());
-                                    ASSERT_FALSE(err);
+                                    check_error(err);
                             });
 
                           mtx::events::msg::Emote emote;
@@ -643,7 +620,7 @@ TEST(ClientAPI, SendMessages)
                             emote,
                             [&event_ids](const mtx::responses::EventId &res, ErrType err) {
                                     event_ids.push_back(res.event_id.toString());
-                                    ASSERT_FALSE(err);
+                                    check_error(err);
                             });
 
                           while (event_ids.size() != 2)
@@ -655,7 +632,7 @@ TEST(ClientAPI, SendMessages)
                             false,
                             0,
                             [room_id, event_ids](const mtx::responses::Sync &res, ErrType err) {
-                                    ASSERT_FALSE(err);
+                                    check_error(err);
 
                                     auto ids = get_event_ids(
                                       res.rooms.join.at(room_id.toString()).timeline.events);