From ffab033a0dc21e3012fe3fa6483d3307b45ed0e4 Mon Sep 17 00:00:00 2001
From: Sergey Yakubov <sergey.yakubov@desy.de>
Date: Sun, 11 Feb 2018 11:49:35 +0100
Subject: [PATCH] add Error class

---
 common/cpp/include/common/error.h             |  37 ++++++
 common/cpp/include/database/database.h        |  31 ++---
 common/cpp/include/system_wrappers/io.h       |  24 ++--
 .../cpp/include/system_wrappers/system_io.h   |   8 +-
 common/cpp/include/unittests/MockIO.h         |  23 ++--
 common/cpp/src/database/database.cpp          |   6 +-
 common/cpp/src/database/mongodb_client.cpp    |  46 +++----
 common/cpp/src/database/mongodb_client.h      |  14 +--
 common/cpp/src/system_io/system_io.cpp        |  33 +++--
 common/cpp/src/system_io/system_io_linux.cpp  |  16 +--
 .../cpp/src/system_io/system_io_windows.cpp   |  36 +++---
 .../worker/getnext_broker/getnext_broker.cpp  |   6 +-
 .../worker/process_folder/process_folder.cpp  |  17 ++-
 tests/common/cpp/src/testing.cpp              |  17 ++-
 tests/mongo_db/connect/CMakeLists.txt         |   4 +-
 tests/mongo_db/connect/connect_mongodb.cpp    |  29 ++---
 tests/mongo_db/insert/CMakeLists.txt          |   4 +-
 tests/mongo_db/insert/insert_mongodb.cpp      |  27 ++--
 .../read_file_content/CMakeLists.txt          |   2 +-
 .../read_file_content/read_file_content.cpp   |  25 +---
 .../read_files_in_folder/CMakeLists.txt       |   2 +-
 .../read_folder_content.cpp                   |  27 ++--
 .../content_multithread.cpp                   |  19 +--
 .../curl_httpclient_get.cpp                   |   6 +-
 .../next_multithread_broker.cpp               |   6 +-
 .../next_multithread_folder.cpp               |   4 +-
 worker/api/cpp/CMakeLists.txt                 |   4 +-
 worker/api/cpp/include/worker/data_broker.h   |  37 +++---
 worker/api/cpp/src/broker_helpers.cpp         |  31 -----
 worker/api/cpp/src/broker_helpers.h           |  17 ---
 worker/api/cpp/src/curl_http_client.cpp       |  10 +-
 worker/api/cpp/src/curl_http_client.h         |   2 +-
 worker/api/cpp/src/data_broker.cpp            |  18 +--
 worker/api/cpp/src/folder_data_broker.cpp     |  37 +++---
 worker/api/cpp/src/folder_data_broker.h       |   6 +-
 worker/api/cpp/src/http_client.cpp            |  24 ++--
 worker/api/cpp/src/http_client.h              |   4 +-
 worker/api/cpp/src/http_error.cpp             |   7 ++
 worker/api/cpp/src/http_error.h               |  22 ++++
 worker/api/cpp/src/server_data_broker.cpp     |  31 +++--
 worker/api/cpp/src/server_data_broker.h       |   6 +-
 worker/api/cpp/unittests/MockHttpClient.h     |   5 +-
 .../api/cpp/unittests/test_folder_broker.cpp  |  76 ++++++-----
 .../api/cpp/unittests/test_server_broker.cpp  |  26 ++--
 worker/api/cpp/unittests/test_worker_api.cpp  |  39 +++---
 .../folder_to_db/src/folder_db_importer.cpp   | 110 +++++-----------
 .../folder_to_db/src/folder_db_importer.h     |  46 +++----
 worker/tools/folder_to_db/src/main.cpp        |   2 +-
 .../unittests/test_folder_to_db.cpp           | 118 ++++++++++--------
 49 files changed, 565 insertions(+), 582 deletions(-)
 create mode 100644 common/cpp/include/common/error.h
 delete mode 100644 worker/api/cpp/src/broker_helpers.cpp
 delete mode 100644 worker/api/cpp/src/broker_helpers.h
 create mode 100644 worker/api/cpp/src/http_error.cpp
 create mode 100644 worker/api/cpp/src/http_error.h

diff --git a/common/cpp/include/common/error.h b/common/cpp/include/common/error.h
new file mode 100644
index 000000000..0973b90f6
--- /dev/null
+++ b/common/cpp/include/common/error.h
@@ -0,0 +1,37 @@
+#ifndef HIDRA2_ERROR_H
+#define HIDRA2_ERROR_H
+
+#include <string>
+
+namespace hidra2 {
+
+class ErrorInterface {
+  public:
+    virtual std::string Explain() const noexcept = 0;
+    virtual void Set(const std::string& error) noexcept = 0;
+};
+
+using Error = std::unique_ptr<ErrorInterface>;
+
+class SimpleError: public ErrorInterface {
+  private:
+    std::string error_;
+  public:
+    explicit SimpleError(const std::string& error): error_{error} {
+
+    }
+    std::string Explain() const noexcept override  {
+        return error_;
+    }
+    void Set(const std::string& error)noexcept override  {
+        error_ = error;
+    }
+
+};
+
+inline Error TextError(const std::string& error) {
+    return Error{new SimpleError{error}};
+}
+
+}
+#endif //HIDRA2_ERROR_H
diff --git a/common/cpp/include/database/database.h b/common/cpp/include/database/database.h
index 504b75006..1b8751307 100644
--- a/common/cpp/include/database/database.h
+++ b/common/cpp/include/database/database.h
@@ -4,34 +4,35 @@
 #include <string>
 
 #include "common/data_structs.h"
+#include "common/error.h"
 
 namespace hidra2 {
 
-enum class DBError {
-    KUnknownError,
-    kConnectionError,
-    kInsertError,
-    kDuplicateID,
-    kAlreadyConnected,
-    kNotConnected,
-    kBadAddress,
-    kNoError,
-    kMemoryError
-};
+namespace DBError {
+auto const KUnknownError = "Inknown error";
+auto const kConnectionError = "Connection error";
+auto const kInsertError = "Insert error";
+auto const kDuplicateID = "Duplicate ID";
+auto const kAlreadyConnected = "Already connected";
+auto const kNotConnected = "Not connected";
+auto const kBadAddress = "Bad address";
+auto const kMemoryError = "Memory error";
+
+}
 
 constexpr char kDBCollectionName[] = "data";
 
 class Database {
   public:
-    virtual DBError Connect(const std::string& address, const std::string& database,
-                            const std::string& collection ) = 0;
-    virtual DBError Insert(const FileInfo& file, bool ignore_duplicates) const = 0;
+    virtual Error Connect(const std::string& address, const std::string& database,
+                          const std::string& collection ) = 0;
+    virtual Error Insert(const FileInfo& file, bool ignore_duplicates) const = 0;
     virtual ~Database() = default;
 };
 
 class DatabaseFactory {
   public:
-    virtual std::unique_ptr<Database> Create(DBError* err) const noexcept;
+    virtual std::unique_ptr<Database> Create(Error* err) const noexcept;
     virtual ~DatabaseFactory() = default;
 };
 
diff --git a/common/cpp/include/system_wrappers/io.h b/common/cpp/include/system_wrappers/io.h
index c38cdd982..9b73e407a 100644
--- a/common/cpp/include/system_wrappers/io.h
+++ b/common/cpp/include/system_wrappers/io.h
@@ -8,31 +8,31 @@
 #include <chrono>
 
 #include "common/data_structs.h"
+#include "common/error.h"
 
 namespace hidra2 {
 
-enum class IOErrors {
-    kNoError,
-    kFileNotFound,
-    kReadError,
-    kPermissionDenied,
-    kUnknownError,
-    kMemoryAllocationError
-};
+namespace IOErrors {
+auto const kFileNotFound = "File not found";
+auto const kReadError = "Read error";
+auto const kPermissionDenied = "Permission denied";
+auto const kUnknownError = "Unknown error";
+auto const kMemoryAllocationError = "Memory Allocation Error";
+}
 
-IOErrors IOErrorFromErrno();
+Error IOErrorFromErrno();
 
 
 class IO {
   public:
 
-    virtual FileData GetDataFromFile(const std::string& fname, uint64_t fsize, IOErrors* err) const noexcept = 0;
-    virtual uint64_t Read(int fd, uint8_t* array, uint64_t fsize, IOErrors* err) const noexcept = 0;
+    virtual FileData GetDataFromFile(const std::string& fname, uint64_t fsize, Error* err) const noexcept = 0;
+    virtual uint64_t Read(int fd, uint8_t* array, uint64_t fsize, Error* err) const noexcept = 0;
     virtual int open(const char* __file, int __oflag) const noexcept = 0;
     virtual int close(int __fd) const noexcept = 0;
 
 // this is not standard function - to be implemented differently in windows and linux
-    virtual FileInfos FilesInFolder(const std::string& folder, IOErrors* err) const = 0;
+    virtual FileInfos FilesInFolder(const std::string& folder, Error* err) const = 0;
 };
 
 }
diff --git a/common/cpp/include/system_wrappers/system_io.h b/common/cpp/include/system_wrappers/system_io.h
index 7f74fd582..d15f5fc04 100644
--- a/common/cpp/include/system_wrappers/system_io.h
+++ b/common/cpp/include/system_wrappers/system_io.h
@@ -7,14 +7,14 @@ namespace hidra2 {
 
 class SystemIO final : public IO {
   public:
-    FileData GetDataFromFile(const std::string& fname, uint64_t fsize, IOErrors* err) const noexcept override;
+    FileData GetDataFromFile(const std::string& fname, uint64_t fsize, Error* err) const noexcept override;
     int open(const char* __file, int __oflag) const noexcept override;
     int close(int __fd) const noexcept override;
-    uint64_t Read(int fd, uint8_t* array, uint64_t fsize, IOErrors* err) const noexcept override;
-    std::vector<FileInfo> FilesInFolder(const std::string& folder, IOErrors* err) const override;
+    uint64_t Read(int fd, uint8_t* array, uint64_t fsize, Error* err) const noexcept override;
+    std::vector<FileInfo> FilesInFolder(const std::string& folder, Error* err) const override;
   private:
     void CollectFileInformationRecursivly(const std::string& path,
-                                          std::vector<FileInfo>* files, IOErrors* err) const;
+                                          std::vector<FileInfo>* files, Error* err) const;
     int64_t read(int __fd, void* buf, size_t count) const noexcept;
     int64_t write(int __fd, const void* __buf, size_t __n) const noexcept;
 };
diff --git a/common/cpp/include/unittests/MockIO.h b/common/cpp/include/unittests/MockIO.h
index fbe0b9510..fd60472ea 100644
--- a/common/cpp/include/unittests/MockIO.h
+++ b/common/cpp/include/unittests/MockIO.h
@@ -10,8 +10,11 @@ namespace hidra2 {
 
 class MockIO : public IO {
   public:
-    FileData GetDataFromFile(const std::string& fname, uint64_t fsize, IOErrors* err) const noexcept override {
-        return FileData{GetDataFromFile_t(fname, fsize, err)};
+    FileData GetDataFromFile(const std::string& fname, uint64_t fsize, Error* err) const noexcept override {
+        SimpleError* error;
+        auto data = GetDataFromFile_t(fname, fsize, &error);
+        err->reset(error);
+        return FileData(data);
     }
     int open(const char* __file, int __oflag) const noexcept override {
         return 0;
@@ -19,16 +22,22 @@ class MockIO : public IO {
     int close(int __fd) const noexcept override {
         return 0;
     }
-    uint64_t Read(int fd, uint8_t* array, uint64_t fsize, IOErrors* err) const noexcept override {
+    uint64_t Read(int fd, uint8_t* array, uint64_t fsize, Error* err) const noexcept override {
         return 0;
     }
 
+    FileInfos FilesInFolder(const std::string& folder, Error* err) const override {
+        SimpleError* error;
+        auto data = FilesInFolder_t(folder, &error);
+        err->reset(error);
+        return data;
+    }
     MOCK_CONST_METHOD3(GetDataFromFile_t,
-                       uint8_t* (const std::string& fname, uint64_t fsize, IOErrors* err));
-    MOCK_CONST_METHOD2(FilesInFolder,
+                       uint8_t* (const std::string& fname, uint64_t fsize, SimpleError** err));
+    MOCK_CONST_METHOD2(FilesInFolder_t,
                        FileInfos(
-                           const std::string& folder, IOErrors
-                           *err));
+                           const std::string& folder, hidra2::SimpleError
+                           ** err));
 
     MOCK_CONST_METHOD3(read_t,
                        int64_t(int
diff --git a/common/cpp/src/database/database.cpp b/common/cpp/src/database/database.cpp
index 5d4dfa61a..f30575e0f 100644
--- a/common/cpp/src/database/database.cpp
+++ b/common/cpp/src/database/database.cpp
@@ -3,13 +3,13 @@
 
 namespace hidra2 {
 
-std::unique_ptr<Database> DatabaseFactory::Create(DBError* err) const noexcept {
+std::unique_ptr<Database> DatabaseFactory::Create(Error* err) const noexcept {
     std::unique_ptr<Database> p = nullptr;
     try {
         p.reset(new MongoDBClient());
-        *err = DBError::kNoError;
+        *err = nullptr;
     } catch (...) {
-        *err = DBError::kMemoryError;
+        *err = TextError(DBError::kMemoryError);
     }
     return p;
 };
diff --git a/common/cpp/src/database/mongodb_client.cpp b/common/cpp/src/database/mongodb_client.cpp
index 07e2b9bba..f9d22d084 100644
--- a/common/cpp/src/database/mongodb_client.cpp
+++ b/common/cpp/src/database/mongodb_client.cpp
@@ -13,7 +13,7 @@ MongoDbInstance::~MongoDbInstance() {
     mongoc_cleanup ();
 }
 
-DBError MongoDBClient::Ping() {
+Error MongoDBClient::Ping() {
     bson_t* command, reply;
     bson_error_t error;
     bool retval;
@@ -25,21 +25,21 @@ DBError MongoDBClient::Ping() {
     bson_destroy (&reply);
     bson_destroy (command);
 
-    return !retval ? DBError::kConnectionError : DBError::kNoError;
+    return !retval ? TextError(DBError::kConnectionError) : nullptr;
 
 }
 MongoDBClient::MongoDBClient() {
     MongoDbInstance::Instantiate();
 }
 
-DBError MongoDBClient::InitializeClient(const string& address) {
+Error MongoDBClient::InitializeClient(const string& address) {
     auto uri_str = DBAddress(address);
     client_ = mongoc_client_new (uri_str.c_str());
 
     if (client_ == nullptr) {
-        return DBError::kBadAddress;
+        return TextError(DBError::kBadAddress);
     }
-    return DBError::kNoError;
+    return nullptr;
 
 }
 
@@ -49,29 +49,29 @@ void MongoDBClient::InitializeCollection(const string& database_name,
                                                 collection_name.c_str());
 }
 
-DBError MongoDBClient::TryConnectDatabase() {
+Error MongoDBClient::TryConnectDatabase() {
     auto err = Ping();
-    if (err == DBError::kNoError) {
+    if (err == nullptr) {
         connected_ = true;
     }
     return err;
 }
 
-DBError MongoDBClient::Connect(const string& address, const string& database_name,
-                               const string& collection_name) {
+Error MongoDBClient::Connect(const string& address, const string& database_name,
+                             const string& collection_name) {
     if (connected_) {
-        return DBError::kAlreadyConnected;
+        return TextError(DBError::kAlreadyConnected);
     }
 
     auto err = InitializeClient(address);
-    if (err != DBError::kNoError) {
+    if (err) {
         return err;
     }
 
     InitializeCollection(database_name, collection_name);
 
     err = TryConnectDatabase();
-    if (err != DBError::kNoError) {
+    if (err) {
         CleanUp();
     }
     return err;
@@ -86,40 +86,40 @@ void MongoDBClient::CleanUp() {
     mongoc_client_destroy (client_);
 }
 
-bson_p PrepareBsonDocument(const FileInfo& file, DBError* err) {
+bson_p PrepareBsonDocument(const FileInfo& file, Error* err) {
     auto s = file.Json();
     auto json = reinterpret_cast<const uint8_t*>(s.c_str());
     auto bson = bson_new_from_json(json, -1, nullptr);
     if (!bson) {
-        *err = DBError::kInsertError;
+        *err = TextError(DBError::kInsertError);
         return nullptr;
     }
 
-    *err = DBError::kNoError;
+    *err = nullptr;
     return bson_p{bson};
 }
 
-DBError MongoDBClient::InsertBsonDocument(const bson_p& document, bool ignore_duplicates) const {
+Error MongoDBClient::InsertBsonDocument(const bson_p& document, bool ignore_duplicates) const {
     bson_error_t mongo_err;
     if (!mongoc_collection_insert_one(collection_, document.get(), NULL, NULL, &mongo_err)) {
         if (mongo_err.code == MONGOC_ERROR_DUPLICATE_KEY) {
-            return ignore_duplicates ? DBError::kNoError : DBError::kDuplicateID;
+            return ignore_duplicates ? nullptr : TextError(DBError::kDuplicateID);
         }
-        return DBError::kInsertError;
+        return TextError(DBError::kInsertError);
     }
 
-    return DBError::kNoError;
+    return nullptr;
 }
 
 
-DBError MongoDBClient::Insert(const FileInfo& file, bool ignore_duplicates) const {
+Error MongoDBClient::Insert(const FileInfo& file, bool ignore_duplicates) const {
     if (!connected_) {
-        return DBError::kNotConnected;
+        return TextError(DBError::kNotConnected);
     }
 
-    DBError err;
+    Error err;
     auto document = PrepareBsonDocument(file, &err);
-    if (err != DBError::kNoError) {
+    if (err) {
         return err;
     }
 
diff --git a/common/cpp/src/database/mongodb_client.h b/common/cpp/src/database/mongodb_client.h
index 4144e8ec5..b9c4bc31d 100644
--- a/common/cpp/src/database/mongodb_client.h
+++ b/common/cpp/src/database/mongodb_client.h
@@ -36,9 +36,9 @@ using bson_p = std::unique_ptr<_bson_t, BsonDestroyFunctor>;
 class MongoDBClient final : public Database {
   public:
     MongoDBClient();
-    DBError Connect(const std::string& address, const std::string& database,
-                    const std::string& collection) override;
-    DBError Insert(const FileInfo& file, bool ignore_duplicates) const override;
+    Error Connect(const std::string& address, const std::string& database,
+                  const std::string& collection) override;
+    Error Insert(const FileInfo& file, bool ignore_duplicates) const override;
     ~MongoDBClient() override;
   private:
     mongoc_client_t* client_{nullptr};
@@ -46,12 +46,12 @@ class MongoDBClient final : public Database {
     bool connected_{false};
     void CleanUp();
     std::string DBAddress(const std::string& address) const;
-    DBError InitializeClient(const std::string& address);
+    Error InitializeClient(const std::string& address);
     void InitializeCollection(const std::string& database_name,
                               const std::string& collection_name);
-    DBError Ping();
-    DBError TryConnectDatabase();
-    DBError InsertBsonDocument(const bson_p& document, bool ignore_duplicates) const;
+    Error Ping();
+    Error TryConnectDatabase();
+    Error InsertBsonDocument(const bson_p& document, bool ignore_duplicates) const;
 };
 
 }
diff --git a/common/cpp/src/system_io/system_io.cpp b/common/cpp/src/system_io/system_io.cpp
index 99b20e8bb..0339443e2 100644
--- a/common/cpp/src/system_io/system_io.cpp
+++ b/common/cpp/src/system_io/system_io.cpp
@@ -9,27 +9,26 @@
 
 namespace hidra2 {
 
-IOErrors IOErrorFromErrno() {
-    IOErrors err;
+Error IOErrorFromErrno() {
+    const char* message;
     switch (errno) {
     case 0:
-        err = IOErrors::kNoError;
-        break;
+        return nullptr;
     case ENOENT:
     case ENOTDIR:
-        err = IOErrors::kFileNotFound;
+        message = IOErrors::kFileNotFound;
         break;
     case EACCES:
-        err = IOErrors::kPermissionDenied;
+        message = IOErrors::kPermissionDenied;
         break;
     default:
-        err = IOErrors::kUnknownError;
+        message = IOErrors::kUnknownError;
         break;
     }
-    return err;
+    return TextError(message);
 }
 
-uint64_t SystemIO::Read(int fd, uint8_t* array, uint64_t fsize, IOErrors* err) const noexcept {
+uint64_t SystemIO::Read(int fd, uint8_t* array, uint64_t fsize, Error* err) const noexcept {
     uint64_t totalbytes = 0;
     int64_t readbytes = 0;
     do {
@@ -38,36 +37,36 @@ uint64_t SystemIO::Read(int fd, uint8_t* array, uint64_t fsize, IOErrors* err) c
     } while (readbytes > 0 && totalbytes < fsize);
 
     if (totalbytes != fsize) {
-        *err = IOErrors::kReadError;
+        *err = TextError(IOErrors::kReadError);
     }
     return totalbytes;
 }
 
-FileData SystemIO::GetDataFromFile(const std::string& fname, uint64_t fsize, IOErrors* err) const noexcept {
+FileData SystemIO::GetDataFromFile(const std::string& fname, uint64_t fsize, Error* err) const noexcept {
     errno = 0;
     int fd = open(fname.c_str(), O_RDONLY);
     *err = IOErrorFromErrno();
-    if (*err != IOErrors::kNoError) {
+    if (*err != nullptr) {
         return nullptr;
     }
     uint8_t* data_array = nullptr;
     try {
         data_array = new uint8_t[fsize];
     } catch (...) {
-        *err = IOErrors::kMemoryAllocationError;
+        *err = TextError(IOErrors::kMemoryAllocationError);
         return nullptr;
     }
 
     Read(fd, data_array, fsize, err);
     FileData data{data_array};
-    if (*err != IOErrors::kNoError) {
+    if (*err != nullptr) {
         close(fd);
         return nullptr;
     }
     errno = 0;
     close(fd);
     *err = IOErrorFromErrno();
-    if (*err != IOErrors::kNoError) {
+    if (*err != nullptr) {
         return nullptr;
     }
 
@@ -96,10 +95,10 @@ void AssignIDs(FileInfos* file_list) {
 }
 
 
-FileInfos SystemIO::FilesInFolder(const std::string& folder, IOErrors* err) const {
+FileInfos SystemIO::FilesInFolder(const std::string& folder, Error* err) const {
     FileInfos files{};
     CollectFileInformationRecursivly(folder, &files, err);
-    if (*err != IOErrors::kNoError) {
+    if (*err != nullptr) {
         return {};
     }
     StripBasePath(folder, &files);
diff --git a/common/cpp/src/system_io/system_io_linux.cpp b/common/cpp/src/system_io/system_io_linux.cpp
index e86e08594..abee2bf59 100644
--- a/common/cpp/src/system_io/system_io_linux.cpp
+++ b/common/cpp/src/system_io/system_io_linux.cpp
@@ -46,7 +46,7 @@ void SetFileName(const string& path, const string& name, FileInfo* file_info) {
     file_info->base_name = name;
 }
 
-struct stat FileStat(const string& fname, IOErrors* err) {
+struct stat FileStat(const string& fname, Error* err) {
     struct stat t_stat {};
     errno = 0;
     int res = stat(fname.c_str(), &t_stat);
@@ -56,13 +56,13 @@ struct stat FileStat(const string& fname, IOErrors* err) {
     return t_stat;
 }
 
-FileInfo GetFileInfo(const string& path, const string& name, IOErrors* err) {
+FileInfo GetFileInfo(const string& path, const string& name, Error* err) {
     FileInfo file_info;
 
     SetFileName(path, name, &file_info);
 
     auto t_stat = FileStat(path + "/" + name, err);
-    if (*err != IOErrors::kNoError) {
+    if (*err != nullptr) {
         return FileInfo{};
     }
 
@@ -74,22 +74,22 @@ FileInfo GetFileInfo(const string& path, const string& name, IOErrors* err) {
 }
 
 void ProcessFileEntity(const struct dirent* entity, const std::string& path,
-                       FileInfos* files, IOErrors* err) {
+                       FileInfos* files, Error* err) {
 
-    *err = IOErrors::kNoError;
+    *err = nullptr;
     if (entity->d_type != DT_REG) {
         return;
     }
 
     FileInfo file_info = GetFileInfo(path, entity->d_name, err);
-    if (*err != IOErrors::kNoError) {
+    if (*err != nullptr) {
         return;
     }
     files->push_back(file_info);
 }
 
 void SystemIO::CollectFileInformationRecursivly(const std::string& path,
-                                                FileInfos* files, IOErrors* err)  const {
+                                                FileInfos* files, Error* err)  const {
     errno = 0;
     auto dir = opendir((path).c_str());
     if (dir == nullptr) {
@@ -108,7 +108,7 @@ void SystemIO::CollectFileInformationRecursivly(const std::string& path,
         } else {
             ProcessFileEntity(current_entity, path, files, err);
         }
-        if (*err != IOErrors::kNoError) {
+        if (*err != nullptr) {
             errno = 0;
             closedir(dir);
             return;
diff --git a/common/cpp/src/system_io/system_io_windows.cpp b/common/cpp/src/system_io/system_io_windows.cpp
index 9e08b483e..171ab2838 100644
--- a/common/cpp/src/system_io/system_io_windows.cpp
+++ b/common/cpp/src/system_io/system_io_windows.cpp
@@ -12,32 +12,32 @@ using std::chrono::system_clock;
 
 namespace hidra2 {
 
-IOErrors IOErrorFromGetLastError() {
-    IOErrors err;
+Error IOErrorFromGetLastError() {
+    const char* message;
     switch (GetLastError()) {
     case ERROR_SUCCESS :
-        err = IOErrors::kNoError;
+        message = IOErrors::kNoError;
         break;
     case ERROR_PATH_NOT_FOUND:
     case ERROR_FILE_NOT_FOUND:
-        err = IOErrors::kFileNotFound;
+        message = IOErrors::kFileNotFound;
         break;
     case ERROR_ACCESS_DENIED:
-        err = IOErrors::kPermissionDenied;
+        message = IOErrors::kPermissionDenied;
         break;
     default:
-        err = IOErrors::kUnknownError;
+        message = IOErrors::kUnknownError;
         break;
     }
-    return err;
+    return TextError(message);
 }
 
-IOErrors CheckFileTime(const FILETIME& ft) {
+Error CheckFileTime(const FILETIME& ft) {
     SYSTEMTIME st = {0};
     if (!FileTimeToSystemTime(&ft, &st)) {
         return IOErrorFromGetLastError();
     }
-    return IOErrors::kNoError;
+    return nullptr;
 }
 
 constexpr auto kShift = 11644473600ULL;
@@ -52,10 +52,10 @@ uint64_t GetLinuxNanosecFromWindowsEpoch(ULARGE_INTEGER ull) {
     return (uint64_t)(ull.QuadPart % k100nsInSec) * 100;
 }
 
-std::chrono::system_clock::time_point FileTime2TimePoint(const FILETIME& ft, IOErrors* err) {
+std::chrono::system_clock::time_point FileTime2TimePoint(const FILETIME& ft, Error* err) {
 
     *err = CheckFileTime(ft);
-    if (*err != IOErrors::kNoError) {
+    if (*err) {
         return std::chrono::system_clock::time_point{};
     }
 
@@ -73,7 +73,7 @@ std::chrono::system_clock::time_point FileTime2TimePoint(const FILETIME& ft, IOE
     auto tp = system_clock::time_point
     {std::chrono::duration_cast<std::chrono::system_clock::duration>(d)};
 
-    *err = IOErrors::kNoError;
+    *err = nullptr;
     return tp;
 }
 
@@ -84,16 +84,16 @@ bool IsDirectory(const WIN32_FIND_DATA f) {
 }
 
 void ProcessFileEntity(const WIN32_FIND_DATA f, const std::string& path,
-                       FileInfos* files, IOErrors* err) {
+                       FileInfos* files, Errors* err) {
 
-    *err = IOErrors::kNoError;
+    *err = nullptr;
     if (f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
         return;
     }
 
     FileInfo file_info;
     file_info.modify_date = FileTime2TimePoint(f.ftLastWriteTime, err);
-    if (*err != IOErrors::kNoError) {
+    if (*err) {
         return;
     }
 
@@ -104,7 +104,7 @@ void ProcessFileEntity(const WIN32_FIND_DATA f, const std::string& path,
 
 
 void SystemIO::CollectFileInformationRecursivly(const std::string& path,
-                                                FileInfos* files, IOErrors* err) const {
+                                                FileInfos* files, Error* err) const {
     WIN32_FIND_DATA find_data;
     HANDLE handle = FindFirstFile((path + "\\*.*").c_str(), &find_data);
     if (handle == INVALID_HANDLE_VALUE) {
@@ -118,14 +118,14 @@ void SystemIO::CollectFileInformationRecursivly(const std::string& path,
         } else {
             ProcessFileEntity(find_data, path, files, err);
         }
-        if (*err != IOErrors::kNoError) {
+        if (*err) {
             FindClose(handle);
             return;
         }
     } while (FindNextFile(handle, &find_data));
 
     if (FindClose(handle)) {
-        *err = IOErrors ::kNoError;
+        *err = nullptr;
     } else {
         *err = IOErrorFromGetLastError();
     }
diff --git a/examples/worker/getnext_broker/getnext_broker.cpp b/examples/worker/getnext_broker/getnext_broker.cpp
index 5013c4669..20237acb8 100644
--- a/examples/worker/getnext_broker/getnext_broker.cpp
+++ b/examples/worker/getnext_broker/getnext_broker.cpp
@@ -9,8 +9,8 @@
 
 #include "hidra2_worker.h"
 
-using hidra2::WorkerErrorCode;
 using std::chrono::high_resolution_clock;
+using hidra2::Error;
 
 void WaitThreads(std::vector<std::thread>* threads) {
     for (auto& thread : *threads) {
@@ -22,9 +22,9 @@ std::vector<std::thread> StartThreads(const std::string& server, const std::stri
                                       std::vector<int>* nfiles) {
     auto exec_next = [server, run_name, nfiles](int i) {
         hidra2::FileInfo fi;
-        hidra2::WorkerErrorCode err;
+        Error err;
         auto broker = hidra2::DataBrokerFactory::CreateServerBroker(server, run_name, &err);
-        while (broker->GetNext(&fi, nullptr) == WorkerErrorCode::kOK) {
+        while (broker->GetNext(&fi, nullptr) == nullptr) {
             (*nfiles)[i] ++;
         }
     };
diff --git a/examples/worker/process_folder/process_folder.cpp b/examples/worker/process_folder/process_folder.cpp
index 40bf59482..da04b67c8 100644
--- a/examples/worker/process_folder/process_folder.cpp
+++ b/examples/worker/process_folder/process_folder.cpp
@@ -8,8 +8,8 @@
 
 #include "hidra2_worker.h"
 
-using hidra2::WorkerErrorCode;
 using std::chrono::high_resolution_clock;
+using hidra2::Error;
 
 struct Statistics {
     std::chrono::milliseconds duration_scan;
@@ -27,9 +27,9 @@ std::string ProcessCommandArguments(int argc, char* argv[]) {
 }
 
 std::unique_ptr<hidra2::DataBroker> CreateBroker(const std::string& folder) {
-    hidra2::WorkerErrorCode err;
+    Error err;
     auto broker = hidra2::DataBrokerFactory::CreateFolderBroker(folder, &err);
-    if (err != WorkerErrorCode::kOK) {
+    if (err != nullptr) {
         std::cout << "Cannot create broker" << std::endl;
         exit(EXIT_FAILURE);
     }
@@ -38,10 +38,9 @@ std::unique_ptr<hidra2::DataBroker> CreateBroker(const std::string& folder) {
 }
 
 void ConnectToBrocker(std::unique_ptr<hidra2::DataBroker>* broker, Statistics* statistics) {
-    hidra2::WorkerErrorCode err;
     high_resolution_clock::time_point t1 = high_resolution_clock::now();
-    err = (*broker)->Connect();
-    if (err != WorkerErrorCode::kOK) {
+    Error err = (*broker)->Connect();
+    if (err != nullptr) {
         std::cout << "Cannot connect to broker" << std::endl;
         exit(EXIT_FAILURE);
     }
@@ -50,18 +49,18 @@ void ConnectToBrocker(std::unique_ptr<hidra2::DataBroker>* broker, Statistics* s
 }
 
 void ReadAllData(std::unique_ptr<hidra2::DataBroker>* broker, Statistics* statistics) {
-    hidra2::WorkerErrorCode err;
+    Error err;
     hidra2::FileInfo file_info;
     hidra2::FileData file_data;
     high_resolution_clock::time_point t1 = high_resolution_clock::now();
 
     int nfiles = 0;
     uint64_t size = 0;
-    while ((err = (*broker)->GetNext(&file_info, &file_data)) == WorkerErrorCode::kOK) {
+    while ((err = (*broker)->GetNext(&file_info, &file_data)) == nullptr) {
         nfiles++;
         size += file_info.size;
     }
-    if (err != WorkerErrorCode::kNoData) {
+    if (err->Explain() != hidra2::WorkerErrorMessage::kNoData) {
         std::cout << "Read error" << std::endl;
         exit(EXIT_FAILURE);
     }
diff --git a/tests/common/cpp/src/testing.cpp b/tests/common/cpp/src/testing.cpp
index c97231c9b..3d1a8e7e5 100644
--- a/tests/common/cpp/src/testing.cpp
+++ b/tests/common/cpp/src/testing.cpp
@@ -1,6 +1,7 @@
 #include "testing.h"
 
 #include <iostream>
+#include <algorithm>
 
 namespace hidra2 {
 
@@ -32,8 +33,22 @@ void M_AssertEq(int expected, int got) {
     T_AssertEq(expected, got);
 }
 
+
+std::string EraseSpaces(const std::string& str) {
+    auto tmp = str;
+    auto end_pos = std::remove(tmp.begin(), tmp.end(), ' ');
+    tmp.erase(end_pos, tmp.end());
+    return tmp;
+}
 void M_AssertContains( const std::string& whole, const std::string& sub) {
-    if (whole.find(sub) == std::string::npos) {
+    auto whole_t = EraseSpaces(whole);
+    auto sub_t = EraseSpaces(sub);
+
+    if (whole_t.find(sub_t) == std::string::npos) {
+        std::cerr << "Assert failed:\n"
+                  << "Got (spaces erased):\t'" << whole_t << "'\n"
+                  << "Expected containes (spaces erased):\t'" << sub_t << "'\n";
+
         exit(EXIT_FAILURE);
     }
 }
diff --git a/tests/mongo_db/connect/CMakeLists.txt b/tests/mongo_db/connect/CMakeLists.txt
index 6c2dc7c5b..8e8190485 100644
--- a/tests/mongo_db/connect/CMakeLists.txt
+++ b/tests/mongo_db/connect/CMakeLists.txt
@@ -14,7 +14,7 @@ target_include_directories(${TARGET_NAME} PUBLIC ${HIDRA2_CXX_COMMON_INCLUDE_DIR
 ################################
 
 add_integration_test(${TARGET_NAME} connectOK "127.0.0.1 data test OK")
-add_integration_test(${TARGET_NAME} connectFAILS "127.0.0.0 data test ConnectionError")
-add_integration_test(${TARGET_NAME} connectBadAddress "#?ß// data test BadAddress")
+add_integration_test(${TARGET_NAME} connectFAILS "127.0.0.0 data test Connectionerror")
+add_integration_test(${TARGET_NAME} connectBadAddress "#?ß// data test Badaddress")
 
 
diff --git a/tests/mongo_db/connect/connect_mongodb.cpp b/tests/mongo_db/connect/connect_mongodb.cpp
index 74fab0b98..c39bdd15f 100644
--- a/tests/mongo_db/connect/connect_mongodb.cpp
+++ b/tests/mongo_db/connect/connect_mongodb.cpp
@@ -5,28 +5,17 @@
 #include "testing.h"
 
 
-using hidra2::M_AssertEq;
-using hidra2::DBError;
+using hidra2::M_AssertContains;
+using hidra2::Error;
 
-
-void Assert(DBError error, const std::string& expect) {
+void Assert(const Error& error, const std::string& expect) {
     std::string result;
-    switch (error) {
-    case DBError::kConnectionError:
-        result = "ConnectionError";
-        break;
-    case DBError::kAlreadyConnected:
-        result = "AlreadyConnected";
-        break;
-    case DBError::kBadAddress:
-        result = "BadAddress";
-        break;
-    default:
+    if (error == nullptr) {
         result = "OK";
-        break;
+    } else {
+        result = error->Explain();
     }
-
-    M_AssertEq(expect, result);
+    M_AssertContains(result, expect);
 }
 
 struct Args {
@@ -53,9 +42,9 @@ int main(int argc, char* argv[]) {
     auto err = db.Connect(args.address, args.database_name, args.collection_name);
     Assert(err, args.keyword);
 
-    if (err == DBError::kNoError) {
+    if (err == nullptr) {
         err = db.Connect(args.address, args.database_name, args.collection_name);
-        Assert(err, "AlreadyConnected");
+        Assert(err, hidra2::DBError::kAlreadyConnected);
     }
     return 0;
 }
diff --git a/tests/mongo_db/insert/CMakeLists.txt b/tests/mongo_db/insert/CMakeLists.txt
index 1ff3205b8..0bff4ed1e 100644
--- a/tests/mongo_db/insert/CMakeLists.txt
+++ b/tests/mongo_db/insert/CMakeLists.txt
@@ -15,8 +15,8 @@ target_include_directories(${TARGET_NAME} PUBLIC ${HIDRA2_CXX_COMMON_INCLUDE_DIR
 add_test_cleanup(${TARGET_NAME})
 add_integration_test(${TARGET_NAME} insertOK "OK 1" "OK 2")
 add_integration_test(${TARGET_NAME} insertFailsWhenNotConnected
-        "NotConnected 3"
-        "NotConnected 4")
+        "Notconnected 3"
+        "Notconnected 4")
 add_integration_test(${TARGET_NAME} insertFailsForDuplicateID
         "DuplicateID 6"
         "DuplicateID 5")
diff --git a/tests/mongo_db/insert/insert_mongodb.cpp b/tests/mongo_db/insert/insert_mongodb.cpp
index a9194c3c8..fc49e83fc 100644
--- a/tests/mongo_db/insert/insert_mongodb.cpp
+++ b/tests/mongo_db/insert/insert_mongodb.cpp
@@ -5,29 +5,18 @@
 #include "testing.h"
 
 
-using hidra2::M_AssertEq;
-using hidra2::DBError;
+using hidra2::M_AssertContains;
+using hidra2::Error;
 
 
-void Assert(DBError error, const std::string& expect) {
+void Assert(const Error& error, const std::string& expect) {
     std::string result;
-    switch (error) {
-    case DBError::kInsertError:
-        result = "InsertError";
-        break;
-    case DBError::kNotConnected:
-        result = "NotConnected";
-        break;
-    case DBError::kDuplicateID:
-        result = "DuplicateID";
-        break;
-
-    default:
+    if (error == nullptr) {
         result = "OK";
-        break;
+    } else {
+        result = error->Explain();
     }
-
-    M_AssertEq(expect, result);
+    M_AssertContains(result, expect);
 }
 
 struct Args {
@@ -55,7 +44,7 @@ int main(int argc, char* argv[]) {
     fi.relative_path = "relpath";
     fi.modify_date = std::chrono::system_clock::now();
 
-    if (args.keyword != "NotConnected") {
+    if (args.keyword != "Notconnected") {
         db.Connect("127.0.0.1", "data", "test");
     }
 
diff --git a/tests/system_io/read_file_content/CMakeLists.txt b/tests/system_io/read_file_content/CMakeLists.txt
index 9b1b0b445..8109443ef 100644
--- a/tests/system_io/read_file_content/CMakeLists.txt
+++ b/tests/system_io/read_file_content/CMakeLists.txt
@@ -17,5 +17,5 @@ set_target_properties(${TARGET_NAME} PROPERTIES LINKER_LANGUAGE CXX)
 add_test_setup_cleanup(${TARGET_NAME})
 add_integration_test(${TARGET_NAME} readfile "test/1 123")
 add_integration_test(${TARGET_NAME} filenotfound "test_notexist notfound")
-add_integration_test(${TARGET_NAME} filenoaccess "file_noaccess noaccess")
+add_integration_test(${TARGET_NAME} filenoaccess "file_noaccess Permissiondenied")
 
diff --git a/tests/system_io/read_file_content/read_file_content.cpp b/tests/system_io/read_file_content/read_file_content.cpp
index 9d19970f3..065e94328 100644
--- a/tests/system_io/read_file_content/read_file_content.cpp
+++ b/tests/system_io/read_file_content/read_file_content.cpp
@@ -4,8 +4,6 @@
 #include "testing.h"
 
 using hidra2::SystemIO;
-using hidra2::IOErrors;
-using hidra2::M_AssertEq;
 
 int main(int argc, char* argv[]) {
     if (argc != 3) {
@@ -14,32 +12,19 @@ int main(int argc, char* argv[]) {
     }
     std::string expect{argv[2]};
 
-    IOErrors err;
+    hidra2::Error err;
     auto io = std::unique_ptr<SystemIO> {new SystemIO};
     auto data = io->GetDataFromFile(argv[1], expect.size(), &err);
 
     std::string result;
 
-    switch (err) {
-    case IOErrors::kFileNotFound:
-        result = "notfound";
-        break;
-    case IOErrors::kNoError:
+    if (err == nullptr) {
         for(unsigned int i = 0; i < expect.size(); i++)
             result += data[i];
-        break;
-    case IOErrors::kPermissionDenied:
-        result = "noaccess";
-        break;
-    case IOErrors::kReadError:
-        result = "readerror";
-        break;
-
-    default:
-        result = "";
-        break;
+    } else {
+        result = err->Explain();
     }
 
-    M_AssertEq(expect, result);
+    hidra2::M_AssertContains(result, expect);
     return 0;
 }
diff --git a/tests/system_io/read_files_in_folder/CMakeLists.txt b/tests/system_io/read_files_in_folder/CMakeLists.txt
index b87f07381..a0065e1f8 100644
--- a/tests/system_io/read_files_in_folder/CMakeLists.txt
+++ b/tests/system_io/read_files_in_folder/CMakeLists.txt
@@ -23,5 +23,5 @@ ENDIF(WIN32)
 
 
 add_integration_test(${TARGET_NAME} foldernotfound "test_notexist notfound")
-add_integration_test(${TARGET_NAME} foldernoaccess "test_noaccess1 noaccess")
+add_integration_test(${TARGET_NAME} foldernoaccess "test_noaccess1 Permissiondenied")
 
diff --git a/tests/system_io/read_files_in_folder/read_folder_content.cpp b/tests/system_io/read_files_in_folder/read_folder_content.cpp
index 71cdc303e..25ac8245b 100644
--- a/tests/system_io/read_files_in_folder/read_folder_content.cpp
+++ b/tests/system_io/read_files_in_folder/read_folder_content.cpp
@@ -4,9 +4,11 @@
 #include "testing.h"
 
 using hidra2::SystemIO;
-using hidra2::IOErrors;
+using hidra2::Error;
+
 
 using hidra2::M_AssertEq;
+using hidra2::M_AssertContains;
 
 int main(int argc, char* argv[]) {
     if (argc != 3) {
@@ -15,31 +17,22 @@ int main(int argc, char* argv[]) {
     }
     std::string expect{argv[2]};
 
-    IOErrors err;
+    Error err;
     auto io = std::unique_ptr<SystemIO> {new SystemIO};
     auto files = io->FilesInFolder(argv[1], &err);
 
-    std::string result;
-    int64_t id = 0;
-    switch (err) {
-    case IOErrors::kFileNotFound:
-        result = "notfound";
-        break;
-    case IOErrors::kNoError:
+    std::string result{};
+    if (err == nullptr) {
+        int64_t id = 0;
         for(auto file_info : files) {
             M_AssertEq(file_info.id, ++id);
             result += file_info.relative_path + file_info.base_name;
         }
-        break;
-    case IOErrors::kPermissionDenied:
-        result = "noaccess";
-        break;
-    default:
-        result = "";
-        break;
+    } else {
+        result = err->Explain();
     }
 
-    M_AssertEq(expect, result);
+    M_AssertContains(result, expect);
 
     return 0;
 }
diff --git a/tests/worker/connect_multithread/content_multithread.cpp b/tests/worker/connect_multithread/content_multithread.cpp
index e4bfcceb8..ef63c6222 100644
--- a/tests/worker/connect_multithread/content_multithread.cpp
+++ b/tests/worker/connect_multithread/content_multithread.cpp
@@ -6,16 +6,19 @@
 #include "testing.h"
 
 using hidra2::M_AssertEq;
-using hidra2::WorkerErrorCode;
 
-void Assert(std::vector<WorkerErrorCode>& errors, int nthreads) {
+void Assert(std::vector<hidra2::Error>& errors, int nthreads) {
     int count_ok = (int) std::count(std::begin(errors),
                                     std::end(errors),
-                                    WorkerErrorCode::kOK);
+                                    nullptr);
+
+    int count_already_connected = 0;
+    for (auto& error : errors) {
+        if (!error) continue;
+        if (error->Explain().find(hidra2::WorkerErrorMessage::kSourceAlreadyConnected) != std::string::npos)
+            count_already_connected++;
+    }
 
-    int count_already_connected = (int) std::count(std::begin(errors),
-                                                   std::end(errors),
-                                                   WorkerErrorCode::kSourceAlreadyConnected);
     M_AssertEq(1, count_ok);
     M_AssertEq(nthreads - 1, count_already_connected);
 }
@@ -39,10 +42,10 @@ int main(int argc, char* argv[]) {
 
     auto args = GetArgs(argc, argv);
 
-    hidra2::WorkerErrorCode err;
+    hidra2::Error err;
     auto broker = hidra2::DataBrokerFactory::CreateFolderBroker(args.folder, &err);
 
-    std::vector<WorkerErrorCode>errors(args.nthreads, WorkerErrorCode::kUnknownIOError);
+    std::vector<hidra2::Error>errors(args.nthreads);
 
     std::vector<std::thread> threads;
     for (int i = 0; i < args.nthreads; i++) {
diff --git a/tests/worker/curl_http_client_get/curl_httpclient_get.cpp b/tests/worker/curl_http_client_get/curl_httpclient_get.cpp
index 1eb59073a..057c474f1 100644
--- a/tests/worker/curl_http_client_get/curl_httpclient_get.cpp
+++ b/tests/worker/curl_http_client_get/curl_httpclient_get.cpp
@@ -7,8 +7,6 @@
 using hidra2::M_AssertEq;
 using hidra2::M_AssertContains;
 
-using hidra2::WorkerErrorCode;
-
 struct Args {
     std::string uri;
     int code;
@@ -31,14 +29,14 @@ int main(int argc, char* argv[]) {
 
     auto args = GetArgs(argc, argv);
 
-    WorkerErrorCode err;
+    hidra2::Error err;
     auto broker = hidra2::DataBrokerFactory::CreateServerBroker(args.uri, "", &err);
     auto server_broker = static_cast<hidra2::ServerDataBroker*>(broker.get());
 
     hidra2::HttpCode code;
     auto responce = server_broker->httpclient__->Get(args.uri, &code, &err);
 
-    if (err != WorkerErrorCode::kOK) {
+    if (err != nullptr) {
         M_AssertEq("clienterror", args.answer);
         M_AssertContains(responce, "Could");
         return 0;
diff --git a/tests/worker/next_multithread_broker/next_multithread_broker.cpp b/tests/worker/next_multithread_broker/next_multithread_broker.cpp
index 49d543ec1..c1def928f 100644
--- a/tests/worker/next_multithread_broker/next_multithread_broker.cpp
+++ b/tests/worker/next_multithread_broker/next_multithread_broker.cpp
@@ -8,8 +8,6 @@
 using hidra2::M_AssertEq;
 using hidra2::M_AssertTrue;
 
-using hidra2::WorkerErrorCode;
-
 void Assert(std::vector<hidra2::FileInfos> file_infos, int nthreads, int nfiles) {
     std::vector<std::string> expect, result;
     for (int i = 1; i <= nfiles; i++) {
@@ -47,13 +45,13 @@ Args GetArgs(int argc, char* argv[]) {
 }
 
 void GetAllFromBroker(const Args& args) {
-    hidra2::WorkerErrorCode err;
+    hidra2::Error err;
     auto broker = hidra2::DataBrokerFactory::CreateServerBroker(args.server, args.run_name, &err);
 
     std::vector<hidra2::FileInfos>file_infos(args.nthreads);
     auto exec_next = [&](int i) {
         hidra2::FileInfo fi;
-        while ((err = broker->GetNext(&fi, nullptr)) == WorkerErrorCode::kOK) {
+        while ((err = broker->GetNext(&fi, nullptr)) == nullptr) {
             file_infos[i].emplace_back(fi);
         }
     };
diff --git a/tests/worker/next_multithread_folder/next_multithread_folder.cpp b/tests/worker/next_multithread_folder/next_multithread_folder.cpp
index 59b168fa4..95ec52494 100644
--- a/tests/worker/next_multithread_folder/next_multithread_folder.cpp
+++ b/tests/worker/next_multithread_folder/next_multithread_folder.cpp
@@ -8,8 +8,6 @@
 using hidra2::M_AssertEq;
 using hidra2::M_AssertTrue;
 
-using hidra2::WorkerErrorCode;
-
 void Assert(std::vector<hidra2::FileInfo> file_infos, int nthreads) {
     int nfiles = (int) file_infos.size();
     M_AssertEq(nthreads, nfiles);
@@ -41,7 +39,7 @@ Args GetArgs(int argc, char* argv[]) {
 }
 
 void GetAllFromBroker(const Args& args) {
-    hidra2::WorkerErrorCode err;
+    hidra2::Error err;
     auto broker = hidra2::DataBrokerFactory::CreateFolderBroker(args.folder, &err);
     broker->Connect();
 
diff --git a/worker/api/cpp/CMakeLists.txt b/worker/api/cpp/CMakeLists.txt
index 8404ee9e4..60aeac037 100644
--- a/worker/api/cpp/CMakeLists.txt
+++ b/worker/api/cpp/CMakeLists.txt
@@ -5,8 +5,8 @@ set(SOURCE_FILES
         src/http_client.cpp
         src/folder_data_broker.cpp
         src/server_data_broker.cpp
-        src/broker_helpers.cpp
-        src/curl_http_client.cpp)
+        src/curl_http_client.cpp
+        src/http_error.cpp)
 
 
 ################################
diff --git a/worker/api/cpp/include/worker/data_broker.h b/worker/api/cpp/include/worker/data_broker.h
index 27e9435f1..e0859dcae 100644
--- a/worker/api/cpp/include/worker/data_broker.h
+++ b/worker/api/cpp/include/worker/data_broker.h
@@ -5,36 +5,37 @@
 #include <string>
 
 #include "common/data_structs.h"
+#include "common/error.h"
 
 namespace hidra2 {
 
-enum class WorkerErrorCode {
-    kOK,
-    kMemoryError,
-    kEmptyDatasource,
-    kSourceNotFound,
-    kSourceNotConnected,
-    kSourceAlreadyConnected,
-    kErrorReadingSource,
-    kPermissionDenied,
-    kNoData,
-    kWrongInput,
-    kInternalError,
-    kUnknownIOError
-};
+namespace WorkerErrorMessage {
+
+auto const kMemoryError = "Memory Error";
+auto const kEmptyDatasource = "Empty Data Source";
+auto const kSourceNotFound = "Source Not Found";
+auto const kSourceNotConnected = "Source Not Connacted";
+auto const kSourceAlreadyConnected = "Source Already Connected";
+auto const kErrorReadingSource = "Error Reading Source";
+auto const kPermissionDenied = "Permissionn Denied";
+auto const kNoData = "No Data";
+auto const kWrongInput = "Wrong Input";
+auto const kInternalError = "Internal Error";
+auto const kUnknownIOError = "Unknown IO Error";
+}
 
 class DataBroker {
   public:
     //! Connect to the data source - will scan file folders or connect to the database.
 // TODO: do we need this?
-    virtual WorkerErrorCode Connect() = 0;
+    virtual Error Connect() = 0;
     //! Receive next image.
     /*!
       \param info -  where to store image metadata. Can be set to nullptr only image data is needed.
       \param data - where to store image data. Can be set to nullptr only image metadata is needed.
       \return Error if both pointers are nullptr or data cannot be read, WorkerErrorCode::OK otherwise.
     */
-    virtual WorkerErrorCode GetNext(FileInfo* info, FileData* data) = 0;
+    virtual Error GetNext(FileInfo* info, FileData* data) = 0;
     virtual ~DataBroker() = default; // needed for unique_ptr to delete itself
 };
 
@@ -42,10 +43,10 @@ class DataBroker {
 class DataBrokerFactory {
   public:
     static std::unique_ptr<DataBroker> CreateFolderBroker(const std::string& source_name,
-            WorkerErrorCode* return_code) noexcept;
+            Error* error) noexcept;
     static std::unique_ptr<DataBroker> CreateServerBroker(const std::string& server_name,
             const std::string& source_name,
-            WorkerErrorCode* return_code) noexcept;
+            Error* error) noexcept;
 
 };
 
diff --git a/worker/api/cpp/src/broker_helpers.cpp b/worker/api/cpp/src/broker_helpers.cpp
deleted file mode 100644
index c9e8dc8e2..000000000
--- a/worker/api/cpp/src/broker_helpers.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-#include "broker_helpers.h"
-
-namespace hidra2 {
-
-WorkerErrorCode MapIOError(IOErrors io_err) {
-    WorkerErrorCode err;
-    switch (io_err) { // we do not use map due to performance reasons
-    case IOErrors::kNoError:
-        err = WorkerErrorCode::kOK;
-        break;
-    case IOErrors::kFileNotFound:
-        err = WorkerErrorCode::kSourceNotFound;
-        break;
-    case IOErrors::kPermissionDenied:
-        err = WorkerErrorCode::kPermissionDenied;
-        break;
-    case IOErrors::kReadError:
-        err = WorkerErrorCode::kErrorReadingSource;
-        break;
-    case IOErrors::kMemoryAllocationError:
-        err = WorkerErrorCode::kMemoryError;
-        break;
-    default:
-        err = WorkerErrorCode::kUnknownIOError;
-        break;
-    }
-
-    return err;
-}
-
-}
diff --git a/worker/api/cpp/src/broker_helpers.h b/worker/api/cpp/src/broker_helpers.h
deleted file mode 100644
index a6a0b555d..000000000
--- a/worker/api/cpp/src/broker_helpers.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef HIDRA2_IO_MAP_H
-#define HIDRA2_IO_MAP_H
-
-
-#include "system_wrappers/system_io.h"
-#include "worker/data_broker.h"
-
-namespace hidra2 {
-
-WorkerErrorCode MapIOError(IOErrors io_err);
-
-}
-
-
-#endif //HIDRA2_IO_MAP_H
-
-
diff --git a/worker/api/cpp/src/curl_http_client.cpp b/worker/api/cpp/src/curl_http_client.cpp
index 39f6ebdfc..9d40c6ec6 100644
--- a/worker/api/cpp/src/curl_http_client.cpp
+++ b/worker/api/cpp/src/curl_http_client.cpp
@@ -49,18 +49,18 @@ std::string GetCurlError(CURL* curl, CURLcode res, const char* errbuf) {
     }
 }
 
-WorkerErrorCode ProcessCurlResponce(CURL* curl, CURLcode res, const char* errbuf,
-                                    std::string* buffer, HttpCode* responce_code) {
+Error ProcessCurlResponce(CURL* curl, CURLcode res, const char* errbuf,
+                          std::string* buffer, HttpCode* responce_code) {
     if(res == CURLE_OK) {
         *responce_code = GetResponceCode(curl);
-        return WorkerErrorCode::kOK;
+        return nullptr;
     } else {
         *buffer = GetCurlError(curl, res, errbuf);
-        return WorkerErrorCode::kErrorReadingSource;
+        return TextError(WorkerErrorMessage::kErrorReadingSource);
     }
 }
 
-std::string CurlHttpClient::Get(const std::string& uri, HttpCode* responce_code, WorkerErrorCode* err) const noexcept {
+std::string CurlHttpClient::Get(const std::string& uri, HttpCode* responce_code, Error* err) const noexcept {
     std::lock_guard<std::mutex> lock{mutex_};
 
     std::string buffer;
diff --git a/worker/api/cpp/src/curl_http_client.h b/worker/api/cpp/src/curl_http_client.h
index c971704f5..578c03337 100644
--- a/worker/api/cpp/src/curl_http_client.h
+++ b/worker/api/cpp/src/curl_http_client.h
@@ -12,7 +12,7 @@ namespace hidra2 {
 class CurlHttpClient final : public HttpClient {
   public:
     CurlHttpClient();
-    std::string Get(const std::string& uri, HttpCode* responce_code, WorkerErrorCode* err) const noexcept override;
+    std::string Get(const std::string& uri, HttpCode* responce_code, Error* err) const noexcept override;
     virtual ~CurlHttpClient();
   private:
     mutable std::mutex mutex_;
diff --git a/worker/api/cpp/src/data_broker.cpp b/worker/api/cpp/src/data_broker.cpp
index 11de4f01f..409799e2b 100644
--- a/worker/api/cpp/src/data_broker.cpp
+++ b/worker/api/cpp/src/data_broker.cpp
@@ -7,19 +7,21 @@ namespace hidra2 {
 
 template <typename Broker, typename ...Args>
 std::unique_ptr<DataBroker> Create(const std::string& source_name,
-                                   WorkerErrorCode* return_code,
+                                   Error* error,
                                    Args&& ... args) noexcept {
     if (source_name.empty()) {
-        *return_code = WorkerErrorCode::kEmptyDatasource;
+        error->reset(new SimpleError("Empty Data Source"));
+        //*return_code = WorkerErrorMessage::kEmptyDatasource;
         return nullptr;
     }
 
     std::unique_ptr<DataBroker> p = nullptr;
     try {
         p.reset(new Broker(source_name, std::forward<Args>(args)...));
-        *return_code = WorkerErrorCode::kOK;
+        error->reset(nullptr);
     } catch (...) {         // we do not test this part
-        *return_code = WorkerErrorCode::kMemoryError;
+        error->reset(new SimpleError("Memory error"));
+//       *return_code = WorkerErrorMessage::kMemoryError;
     }
 
     return p;
@@ -27,14 +29,14 @@ std::unique_ptr<DataBroker> Create(const std::string& source_name,
 }
 
 std::unique_ptr<DataBroker> DataBrokerFactory::CreateFolderBroker(const std::string& source_name,
-        WorkerErrorCode* return_code) noexcept {
-    return Create<FolderDataBroker>(source_name, return_code);
+        Error* error) noexcept {
+    return Create<FolderDataBroker>(source_name, error);
 };
 
 std::unique_ptr<DataBroker> DataBrokerFactory::CreateServerBroker(const std::string& server_name,
         const std::string& source_name,
-        WorkerErrorCode* return_code) noexcept {
-    return Create<ServerDataBroker>(server_name, return_code, source_name);
+        Error* error) noexcept {
+    return Create<ServerDataBroker>(server_name, error, source_name);
 }
 
 
diff --git a/worker/api/cpp/src/folder_data_broker.cpp b/worker/api/cpp/src/folder_data_broker.cpp
index 9c460c421..11e44d963 100644
--- a/worker/api/cpp/src/folder_data_broker.cpp
+++ b/worker/api/cpp/src/folder_data_broker.cpp
@@ -1,7 +1,6 @@
 #include "folder_data_broker.h"
 
 #include "system_wrappers/system_io.h"
-#include "broker_helpers.h"
 
 namespace hidra2 {
 
@@ -10,59 +9,61 @@ FolderDataBroker::FolderDataBroker(const std::string& source_name) :
 current_file_{ -1} {
 }
 
-WorkerErrorCode FolderDataBroker::Connect() {
+Error FolderDataBroker::Connect() {
     std::lock_guard<std::mutex> lock{mutex_};
 
     if (is_connected_) {
-        return WorkerErrorCode::kSourceAlreadyConnected;
+        return TextError(WorkerErrorMessage::kSourceAlreadyConnected);
     }
 
-    IOErrors io_err;
-    filelist_ = io__->FilesInFolder(base_path_, &io_err);
+    Error error;
+    filelist_ = io__->FilesInFolder(base_path_, &error);
 
-    if (io_err == IOErrors::kNoError) {
+    if (error == nullptr) {
         is_connected_ = true;
+        return nullptr;
     }
-    return MapIOError(io_err);
+
+    return error;
 }
 
-WorkerErrorCode FolderDataBroker::CanGetData(FileInfo* info, FileData* data, int nfile) const noexcept {
+Error FolderDataBroker::CanGetData(FileInfo* info, FileData* data, int nfile) const noexcept {
     if (!is_connected_) {
-        return WorkerErrorCode::kSourceNotConnected;
+        return TextError(WorkerErrorMessage::kSourceNotConnected);
     }
 
     if (info == nullptr) {
-        return WorkerErrorCode::kWrongInput;
+        return TextError(WorkerErrorMessage::kWrongInput);
     }
 
     if (nfile >= (int) filelist_.size()) {
-        return WorkerErrorCode::kNoData;
+        return Error{TextError(WorkerErrorMessage::kNoData)};
     }
-    return WorkerErrorCode::kOK;
+    return nullptr;
 }
 
 
-WorkerErrorCode FolderDataBroker::GetNext(FileInfo* info, FileData* data) {
+Error FolderDataBroker::GetNext(FileInfo* info, FileData* data) {
 // could probably use atomic here, but just to make sure (tests showed no performance difference)
     mutex_.lock();
     int nfile_to_get = ++current_file_;
     mutex_.unlock();
 
     auto err = CanGetData(info, data, nfile_to_get);
-    if (err != WorkerErrorCode::kOK) {
+    if (err != nullptr) {
         return err;
     }
 
     *info = filelist_[nfile_to_get];
 
     if (data == nullptr) {
-        return WorkerErrorCode::kOK;
+        return nullptr;
     }
 
-    IOErrors ioerr;
-    *data = io__->GetDataFromFile(info->FullName(base_path_), info->size, &ioerr);
+    Error error;
+    *data = io__->GetDataFromFile(info->FullName(base_path_), info->size, &error);
 
-    return MapIOError(ioerr);
+    return error;
 }
 
 
diff --git a/worker/api/cpp/src/folder_data_broker.h b/worker/api/cpp/src/folder_data_broker.h
index 2bcdcfbe5..4ffe1b211 100644
--- a/worker/api/cpp/src/folder_data_broker.h
+++ b/worker/api/cpp/src/folder_data_broker.h
@@ -13,8 +13,8 @@ namespace hidra2 {
 class FolderDataBroker final : public hidra2::DataBroker {
   public:
     explicit FolderDataBroker(const std::string& source_name);
-    WorkerErrorCode Connect() override;
-    WorkerErrorCode GetNext(FileInfo* info, FileData* data) override;
+    Error Connect() override;
+    Error GetNext(FileInfo* info, FileData* data) override;
 
     std::unique_ptr<hidra2::IO> io__; // modified in testings to mock system calls,otherwise do not touch
 
@@ -23,7 +23,7 @@ class FolderDataBroker final : public hidra2::DataBroker {
     bool is_connected_;
     int current_file_;
     FileInfos  filelist_;
-    WorkerErrorCode CanGetData(FileInfo* info, FileData* data, int nfile) const noexcept;
+    Error CanGetData(FileInfo* info, FileData* data, int nfile) const noexcept;
     std::mutex mutex_;
 };
 
diff --git a/worker/api/cpp/src/http_client.cpp b/worker/api/cpp/src/http_client.cpp
index 1a61473fa..7b9c98368 100644
--- a/worker/api/cpp/src/http_client.cpp
+++ b/worker/api/cpp/src/http_client.cpp
@@ -1,23 +1,29 @@
 #include "http_client.h"
-
+#include "http_error.h"
 namespace hidra2 {
 
-WorkerErrorCode HttpCodeToWorkerError(const HttpCode& code) {
+Error HttpCodeToWorkerError(const HttpCode& code) {
+    const char* message;
     switch (code) {
     case HttpCode::OK:
-        return WorkerErrorCode::kOK;
+        return nullptr;
     case HttpCode::BadRequest:
-        return WorkerErrorCode::kWrongInput;
+        message = WorkerErrorMessage::kWrongInput;
+        break;
     case HttpCode::InternalServerError:
-        return WorkerErrorCode::kErrorReadingSource;
+        message = WorkerErrorMessage::kErrorReadingSource;
+        break;
     case HttpCode::NoContent:
-        return WorkerErrorCode::kNoData;
+        message = WorkerErrorMessage::kNoData;
+        break;
     case HttpCode::NotFound:
-        return WorkerErrorCode::kSourceNotFound;
+        message = WorkerErrorMessage::kSourceNotFound;
+        break;
     default:
-        return WorkerErrorCode::kErrorReadingSource;
+        message = WorkerErrorMessage::kErrorReadingSource;
+        break;
     }
-
+    return Error{new HttpError(message, code)};
 }
 
 }
diff --git a/worker/api/cpp/src/http_client.h b/worker/api/cpp/src/http_client.h
index 41fa0ba97..725af4601 100644
--- a/worker/api/cpp/src/http_client.h
+++ b/worker/api/cpp/src/http_client.h
@@ -9,12 +9,12 @@ enum class HttpCode;
 
 class HttpClient {
   public:
-    virtual std::string Get(const std::string& uri, HttpCode* responce_code, WorkerErrorCode* err) const noexcept = 0;
+    virtual std::string Get(const std::string& uri, HttpCode* responce_code, Error* err) const noexcept = 0;
     virtual ~HttpClient() = default;
 
 };
 
-WorkerErrorCode HttpCodeToWorkerError(const HttpCode& code);
+Error HttpCodeToWorkerError(const HttpCode& code);
 
 enum class HttpCode : int {
     Continue           = 100,
diff --git a/worker/api/cpp/src/http_error.cpp b/worker/api/cpp/src/http_error.cpp
new file mode 100644
index 000000000..72189fc37
--- /dev/null
+++ b/worker/api/cpp/src/http_error.cpp
@@ -0,0 +1,7 @@
+#include "http_error.h"
+
+namespace hidra2 {
+
+
+
+}
\ No newline at end of file
diff --git a/worker/api/cpp/src/http_error.h b/worker/api/cpp/src/http_error.h
new file mode 100644
index 000000000..2c3f5f362
--- /dev/null
+++ b/worker/api/cpp/src/http_error.h
@@ -0,0 +1,22 @@
+#ifndef HIDRA2_HTTP_ERROR_H
+#define HIDRA2_HTTP_ERROR_H
+
+#include "common/error.h"
+#include "http_client.h"
+
+namespace hidra2 {
+
+class HttpError: public SimpleError {
+  public:
+    HttpError(const std::string& error, HttpCode http_code): SimpleError{error}, http_code_{http_code} {
+    }
+    HttpCode GetCode() const {
+        return http_code_;
+    }
+  private:
+    HttpCode http_code_;
+};
+
+}
+
+#endif //HIDRA2_HTTP_ERROR_H
diff --git a/worker/api/cpp/src/server_data_broker.cpp b/worker/api/cpp/src/server_data_broker.cpp
index 612ea1060..8cd9c3efe 100644
--- a/worker/api/cpp/src/server_data_broker.cpp
+++ b/worker/api/cpp/src/server_data_broker.cpp
@@ -1,7 +1,6 @@
 #include "server_data_broker.h"
 #include "system_wrappers/system_io.h"
 #include "curl_http_client.h"
-#include "broker_helpers.h"
 
 namespace hidra2 {
 
@@ -11,48 +10,48 @@ ServerDataBroker::ServerDataBroker(const std::string& server_uri,
 server_uri_{server_uri}, source_name_{source_name} {
 }
 
-WorkerErrorCode ServerDataBroker::Connect() {
-    return WorkerErrorCode::kOK;
+Error ServerDataBroker::Connect() {
+    return nullptr;
 }
 
-WorkerErrorCode ServerDataBroker::GetFileInfoFromServer(FileInfo* info, const std::string& operation) {
+Error ServerDataBroker::GetFileInfoFromServer(FileInfo* info, const std::string& operation) {
     std::string full_uri = server_uri_ + "/database/" + source_name_ + "/" + operation;
-    WorkerErrorCode err;
+    Error err;
     HttpCode code;
     auto responce = httpclient__->Get(full_uri, &code, &err);
 
-    if (err != WorkerErrorCode::kOK) {
+    if (err != nullptr) {
         return err;
     }
 
     err = HttpCodeToWorkerError(code);
-    if (err != WorkerErrorCode::kOK) {
+    if (err != nullptr) {
         return err;
     }
 
     if (!info->SetFromJson(responce)) {
-        return WorkerErrorCode::kErrorReadingSource;
+        return TextError(WorkerErrorMessage::kErrorReadingSource);
     }
-    return WorkerErrorCode::kOK;
+    return nullptr;
 }
 
-WorkerErrorCode ServerDataBroker::GetNext(FileInfo* info, FileData* data) {
+Error ServerDataBroker::GetNext(FileInfo* info, FileData* data) {
     if (info == nullptr) {
-        return WorkerErrorCode::kWrongInput;
+        return TextError(WorkerErrorMessage::kWrongInput);
     }
 
     auto  err = GetFileInfoFromServer(info, "next");
-    if (err != WorkerErrorCode::kOK) {
+    if (err != nullptr) {
         return err;
     }
 
     if (data == nullptr) {
-        return WorkerErrorCode::kOK;
+        return nullptr;
     }
 
-    IOErrors ioerr;
-    *data = io__->GetDataFromFile(info->FullName(""), info->size, &ioerr);
-    return hidra2::MapIOError(ioerr);
+    Error error;
+    *data = io__->GetDataFromFile(info->FullName(""), info->size, &error);
+    return error;
 }
 
 }
\ No newline at end of file
diff --git a/worker/api/cpp/src/server_data_broker.h b/worker/api/cpp/src/server_data_broker.h
index 55cd97317..d77fff8bf 100644
--- a/worker/api/cpp/src/server_data_broker.h
+++ b/worker/api/cpp/src/server_data_broker.h
@@ -11,12 +11,12 @@ namespace hidra2 {
 class ServerDataBroker final : public hidra2::DataBroker {
   public:
     explicit ServerDataBroker(const std::string& server_uri, const std::string& source_name);
-    WorkerErrorCode Connect() override;
-    WorkerErrorCode GetNext(FileInfo* info, FileData* data) override;
+    Error Connect() override;
+    Error GetNext(FileInfo* info, FileData* data) override;
     std::unique_ptr<hidra2::IO> io__; // modified in testings to mock system calls,otherwise do not touch
     std::unique_ptr<hidra2::HttpClient> httpclient__;
   private:
-    WorkerErrorCode GetFileInfoFromServer(FileInfo* info, const std::string& operation);
+    Error GetFileInfoFromServer(FileInfo* info, const std::string& operation);
     std::string server_uri_;
     std::string source_name_;
 };
diff --git a/worker/api/cpp/unittests/MockHttpClient.h b/worker/api/cpp/unittests/MockHttpClient.h
index 06ff805aa..a386321db 100644
--- a/worker/api/cpp/unittests/MockHttpClient.h
+++ b/worker/api/cpp/unittests/MockHttpClient.h
@@ -7,15 +7,16 @@
 #include "../src/http_client.h"
 #include "worker/data_broker.h"
 
+
 namespace hidra2 {
 
 class MockHttpClient : public HttpClient {
   public:
-    std::string Get(const std::string& uri, HttpCode* code, WorkerErrorCode* err) const noexcept override {
+    std::string Get(const std::string& uri, HttpCode* code, Error* err) const noexcept override {
         return Get_t(uri, code, err);
     }
     MOCK_CONST_METHOD3(Get_t,
-                       std::string(const std::string& uri, HttpCode* code, WorkerErrorCode* err));
+                       std::string(const std::string& uri, HttpCode* code, Error* err));
 };
 
 
diff --git a/worker/api/cpp/unittests/test_folder_broker.cpp b/worker/api/cpp/unittests/test_folder_broker.cpp
index 9b3992237..d3a673f43 100644
--- a/worker/api/cpp/unittests/test_folder_broker.cpp
+++ b/worker/api/cpp/unittests/test_folder_broker.cpp
@@ -9,12 +9,13 @@
 using hidra2::DataBrokerFactory;
 using hidra2::DataBroker;
 using hidra2::FolderDataBroker;
-using hidra2::WorkerErrorCode;
 using hidra2::IO;
-using hidra2::IOErrors;
 using hidra2::FileInfos;
 using hidra2::FileInfo;
 using hidra2::FileData;
+using hidra2::Error;
+using hidra2::TextError;
+using hidra2::SimpleError;
 
 using ::testing::AtLeast;
 using ::testing::Eq;
@@ -37,13 +38,16 @@ TEST(FolderDataBroker, SetCorrectIO) {
 class FakeIO: public IO {
   public:
 
-    virtual uint8_t* GetDataFromFileProxy(const std::string& fname, uint64_t fsize, IOErrors* err) const {
-        *err = IOErrors::kNoError;
+    virtual uint8_t* GetDataFromFileProxy(const std::string& fname, uint64_t fsize, SimpleError** err) const {
+        *err = nullptr;
         return nullptr;
     };
 
-    FileData GetDataFromFile(const std::string& fname, uint64_t fsize, IOErrors* err) const noexcept override {
-        return FileData(GetDataFromFileProxy(fname, fsize, err));
+    FileData GetDataFromFile(const std::string& fname, uint64_t fsize, Error* err) const noexcept override {
+        SimpleError* error;
+        auto data = GetDataFromFileProxy(fname, fsize, &error);
+        err->reset(error);
+        return FileData(data);
     };
 
     int open(const char* __file, int __oflag) const noexcept override {
@@ -54,11 +58,11 @@ class FakeIO: public IO {
         return 0;
     };
 
-    uint64_t Read(int fd, uint8_t* array, uint64_t fsize, IOErrors* err) const noexcept override {
+    uint64_t Read(int fd, uint8_t* array, uint64_t fsize, Error* err) const noexcept override {
         return 0;
     };
-    FileInfos FilesInFolder(const std::string& folder, IOErrors* err) const override {
-        *err = IOErrors::kNoError;
+    FileInfos FilesInFolder(const std::string& folder, Error* err) const override {
+        *err = nullptr;
         FileInfos file_infos;
         FileInfo fi;
         fi.size = 100;
@@ -74,32 +78,32 @@ class FakeIO: public IO {
 
 class IOFolderNotFound: public FakeIO {
   public:
-    FileInfos FilesInFolder(const std::string& folder, IOErrors* err) const override {
-        *err = IOErrors::kFileNotFound;
+    FileInfos FilesInFolder(const std::string& folder, Error* err) const override {
+        *err = hidra2::TextError(hidra2::IOErrors::kFileNotFound);
         return {};
     }
 };
 
 class IOFolderUnknownError: public FakeIO {
   public:
-    FileInfos FilesInFolder(const std::string& folder, IOErrors* err) const override {
-        *err = IOErrors::kUnknownError;
+    FileInfos FilesInFolder(const std::string& folder, Error* err) const override {
+        *err = hidra2::TextError(hidra2::IOErrors::kUnknownError);
         return {};
     }
 };
 
 class IOEmptyFolder: public FakeIO {
   public:
-    FileInfos FilesInFolder(const std::string& folder, IOErrors* err) const override {
-        *err = IOErrors::kNoError;
+    FileInfos FilesInFolder(const std::string& folder, Error* err) const override {
+        *err = nullptr;
         return {};
     }
 };
 
 class IOCannotOpenFile: public FakeIO {
   public:
-    FileData GetDataFromFile(const std::string& fname, uint64_t fsize, IOErrors* err) const noexcept override {
-        *err = IOErrors::kPermissionDenied;
+    FileData GetDataFromFile(const std::string& fname, uint64_t fsize, Error* err) const noexcept override {
+        *err = hidra2::TextError(hidra2::IOErrors::kPermissionDenied);
         return {};
     };
 };
@@ -120,7 +124,7 @@ class FolderDataBrokerTests : public Test {
 TEST_F(FolderDataBrokerTests, CanConnect) {
     auto return_code = data_broker->Connect();
 
-    ASSERT_THAT(return_code, Eq(WorkerErrorCode::kOK));
+    ASSERT_THAT(return_code, Eq(nullptr));
 }
 
 TEST_F(FolderDataBrokerTests, CannotConnectTwice) {
@@ -128,7 +132,7 @@ TEST_F(FolderDataBrokerTests, CannotConnectTwice) {
 
     auto return_code = data_broker->Connect();
 
-    ASSERT_THAT(return_code, Eq(WorkerErrorCode::kSourceAlreadyConnected));
+    ASSERT_THAT(return_code->Explain(), Eq(hidra2::WorkerErrorMessage::kSourceAlreadyConnected));
 }
 
 
@@ -137,7 +141,7 @@ TEST_F(FolderDataBrokerTests, CannotConnectWhenNoFolder) {
 
     auto return_code = data_broker->Connect();
 
-    ASSERT_THAT(return_code, Eq(WorkerErrorCode::kSourceNotFound));
+    ASSERT_THAT(return_code->Explain(), Eq(hidra2::IOErrors::kFileNotFound));
 }
 
 TEST_F(FolderDataBrokerTests, ConnectReturnsUnknownIOError) {
@@ -145,13 +149,13 @@ TEST_F(FolderDataBrokerTests, ConnectReturnsUnknownIOError) {
 
     auto return_code = data_broker->Connect();
 
-    ASSERT_THAT(return_code, Eq(WorkerErrorCode::kUnknownIOError));
+    ASSERT_THAT(return_code->Explain(), Eq(hidra2::IOErrors::kUnknownError));
 }
 
 TEST_F(FolderDataBrokerTests, GetNextWithoutConnectReturnsError) {
     auto err = data_broker->GetNext(nullptr, nullptr);
 
-    ASSERT_THAT(err, Eq(WorkerErrorCode::kSourceNotConnected));
+    ASSERT_THAT(err->Explain(), Eq(hidra2::WorkerErrorMessage::kSourceNotConnected));
 }
 
 TEST_F(FolderDataBrokerTests, GetNextWithNullPointersReturnsError) {
@@ -159,7 +163,7 @@ TEST_F(FolderDataBrokerTests, GetNextWithNullPointersReturnsError) {
 
     auto err = data_broker->GetNext(nullptr, nullptr);
 
-    ASSERT_THAT(err, Eq(WorkerErrorCode::kWrongInput));
+    ASSERT_THAT(err->Explain(), Eq(hidra2::WorkerErrorMessage::kWrongInput));
 }
 
 TEST_F(FolderDataBrokerTests, GetNextReturnsFileInfo) {
@@ -168,7 +172,7 @@ TEST_F(FolderDataBrokerTests, GetNextReturnsFileInfo) {
 
     auto err = data_broker->GetNext(&fi, nullptr);
 
-    ASSERT_THAT(err, Eq(WorkerErrorCode::kOK));
+    ASSERT_THAT(err, Eq(nullptr));
     ASSERT_THAT(fi.base_name, Eq("1"));
     ASSERT_THAT(fi.size, Eq(100));
 
@@ -181,7 +185,7 @@ TEST_F(FolderDataBrokerTests, SecondNextReturnsAnotherFileInfo) {
 
     auto err = data_broker->GetNext(&fi, nullptr);
 
-    ASSERT_THAT(err, Eq(WorkerErrorCode::kOK));
+    ASSERT_THAT(err, Eq(nullptr));
     ASSERT_THAT(fi.base_name, Eq("2"));
 }
 
@@ -191,7 +195,7 @@ TEST_F(FolderDataBrokerTests, GetNextFromEmptyFolderReturnsError) {
     FileInfo fi;
 
     auto err = data_broker->GetNext(&fi, nullptr);
-    ASSERT_THAT(err, Eq(WorkerErrorCode::kNoData));
+    ASSERT_THAT(err->Explain(), Eq(hidra2::WorkerErrorMessage::kNoData));
 }
 
 
@@ -202,13 +206,13 @@ TEST_F(FolderDataBrokerTests, GetNextReturnsErrorWhenFilePermissionsDenied) {
     FileData data;
 
     auto err = data_broker->GetNext(&fi, &data);
-    ASSERT_THAT(err, Eq(WorkerErrorCode::kPermissionDenied));
+    ASSERT_THAT(err->Explain(), Eq(hidra2::IOErrors::kPermissionDenied));
 }
 
 
 class OpenFileMock : public FakeIO {
   public:
-    MOCK_CONST_METHOD3(GetDataFromFileProxy, uint8_t* (const std::string&, uint64_t, IOErrors*));
+    MOCK_CONST_METHOD3(GetDataFromFileProxy, uint8_t* (const std::string&, uint64_t, SimpleError**));
 };
 
 
@@ -230,7 +234,7 @@ class GetDataFromFileTests : public Test {
 
 TEST_F(GetDataFromFileTests, GetNextCallsGetDataFileWithFileName) {
     EXPECT_CALL(mock, GetDataFromFileProxy("/path/to/file/1", _, _)).
-    WillOnce(DoAll(testing::SetArgPointee<2>(IOErrors::kNoError), testing::Return(nullptr)));
+    WillOnce(DoAll(testing::SetArgPointee<2>(static_cast<SimpleError*>(nullptr)), testing::Return(nullptr)));
 
     data_broker->GetNext(&fi, &data);
 }
@@ -239,7 +243,7 @@ TEST_F(GetDataFromFileTests, GetNextCallsGetDataFileWithFileName) {
 
 TEST_F(GetDataFromFileTests, GetNextReturnsDataAndInfo) {
     EXPECT_CALL(mock, GetDataFromFileProxy(_, _, _)).
-    WillOnce(DoAll(testing::SetArgPointee<2>(IOErrors::kNoError), testing::Return(new uint8_t[1] {'1'})));
+    WillOnce(DoAll(testing::SetArgPointee<2>(nullptr), testing::Return(new uint8_t[1] {'1'})));
 
     data_broker->GetNext(&fi, &data);
 
@@ -248,22 +252,26 @@ TEST_F(GetDataFromFileTests, GetNextReturnsDataAndInfo) {
 
 }
 
+
+
 TEST_F(GetDataFromFileTests, GetNextReturnsErrorWhenCannotReadData) {
     EXPECT_CALL(mock, GetDataFromFileProxy(_, _, _)).
-    WillOnce(DoAll(testing::SetArgPointee<2>(IOErrors::kReadError), testing::Return(nullptr)));
+    WillOnce(DoAll(testing::SetArgPointee<2>(new SimpleError(hidra2::IOErrors::kReadError)), testing::Return(nullptr)));
 
     auto err = data_broker->GetNext(&fi, &data);
 
-    ASSERT_THAT(err, Eq(WorkerErrorCode::kErrorReadingSource));
+    ASSERT_THAT(err->Explain(), Eq(hidra2::IOErrors::kReadError));
 }
 
+
 TEST_F(GetDataFromFileTests, GetNextReturnsErrorWhenCannotAllocateData) {
     EXPECT_CALL(mock, GetDataFromFileProxy(_, _, _)).
-    WillOnce(DoAll(testing::SetArgPointee<2>(IOErrors::kMemoryAllocationError), testing::Return(nullptr)));
+    WillOnce(DoAll(testing::SetArgPointee<2>(new SimpleError(hidra2::IOErrors::kMemoryAllocationError)),
+                   testing::Return(nullptr)));
 
     auto err = data_broker->GetNext(&fi, &data);
 
-    ASSERT_THAT(err, Eq(WorkerErrorCode::kMemoryError));
+    ASSERT_THAT(err->Explain(), Eq(hidra2::IOErrors::kMemoryAllocationError));
 }
 
 
diff --git a/worker/api/cpp/unittests/test_server_broker.cpp b/worker/api/cpp/unittests/test_server_broker.cpp
index a4a542df9..4f0b6614f 100644
--- a/worker/api/cpp/unittests/test_server_broker.cpp
+++ b/worker/api/cpp/unittests/test_server_broker.cpp
@@ -8,18 +8,19 @@
 #include "../src/curl_http_client.h"
 #include "unittests/MockIO.h"
 #include "MockHttpClient.h"
+#include "../src/http_error.h"
 
 using hidra2::DataBrokerFactory;
 using hidra2::DataBroker;
 using hidra2::ServerDataBroker;
-using hidra2::WorkerErrorCode;
 using hidra2::IO;
-using hidra2::IOErrors;
 using hidra2::FileInfo;
 using hidra2::FileData;
 using hidra2::MockIO;
 using hidra2::MockHttpClient;
 using hidra2::HttpCode;
+using hidra2::HttpError;
+using hidra2::SimpleError;
 
 using ::testing::AtLeast;
 using ::testing::Eq;
@@ -64,7 +65,7 @@ class ServerDataBrokerTests : public Test {
     void MockGet(const std::string& responce) {
         EXPECT_CALL(mock_http_client, Get_t(_, _, _)).WillOnce(DoAll(
                     SetArgPointee<1>(HttpCode::OK),
-                    SetArgPointee<2>(WorkerErrorCode::kOK),
+                    SetArgPointee<2>(nullptr),
                     Return(responce)
                 ));
     }
@@ -73,19 +74,19 @@ class ServerDataBrokerTests : public Test {
 
 TEST_F(ServerDataBrokerTests, CanConnect) {
     auto return_code = data_broker->Connect();
-    ASSERT_THAT(return_code, Eq(WorkerErrorCode::kOK));
+    ASSERT_THAT(return_code, Eq(nullptr));
 }
 
 TEST_F(ServerDataBrokerTests, GetNextReturnsErrorOnWrongInput) {
     auto return_code = data_broker->GetNext(nullptr, nullptr);
-    ASSERT_THAT(return_code, Eq(WorkerErrorCode::kWrongInput));
+    ASSERT_THAT(return_code->Explain(), Eq(hidra2::WorkerErrorMessage::kWrongInput));
 }
 
 
 TEST_F(ServerDataBrokerTests, GetNextUsesCorrectUri) {
     EXPECT_CALL(mock_http_client, Get_t("test/database/dbname/next", _, _)).WillOnce(DoAll(
                 SetArgPointee<1>(HttpCode::OK),
-                SetArgPointee<2>(WorkerErrorCode::kOK),
+                SetArgPointee<2>(nullptr),
                 Return("")));
     data_broker->GetNext(&info, nullptr);
 }
@@ -93,13 +94,13 @@ TEST_F(ServerDataBrokerTests, GetNextUsesCorrectUri) {
 TEST_F(ServerDataBrokerTests, GetNextReturnsErrorFromHttpClient) {
     EXPECT_CALL(mock_http_client, Get_t(_, _, _)).WillOnce(DoAll(
                 SetArgPointee<1>(HttpCode::NotFound),
-                SetArgPointee<2>(WorkerErrorCode::kOK),
+                SetArgPointee<2>(nullptr),
                 Return("")));
 
     auto err = data_broker->GetNext(&info, nullptr);
 
-    ASSERT_THAT(err, Eq(WorkerErrorCode::kSourceNotFound));
-
+    ASSERT_THAT(err->Explain(), Eq(hidra2::WorkerErrorMessage::kSourceNotFound));
+    ASSERT_THAT(dynamic_cast<HttpError*>(err.get())->GetCode(), Eq(HttpCode::NotFound));
 }
 
 FileInfo CreateFI() {
@@ -120,7 +121,7 @@ TEST_F(ServerDataBrokerTests, GetNextReturnsFileInfo) {
 
     auto err = data_broker->GetNext(&info, nullptr);
 
-    ASSERT_THAT(err, Eq(WorkerErrorCode::kOK));
+    ASSERT_THAT(err, Eq(nullptr));
 
     ASSERT_THAT(info.base_name, Eq(to_send.base_name));
     ASSERT_THAT(info.size, Eq(to_send.size));
@@ -134,7 +135,7 @@ TEST_F(ServerDataBrokerTests, GetNextReturnsParseError) {
     MockGet("error_responce");
     auto err = data_broker->GetNext(&info, nullptr);
 
-    ASSERT_THAT(err, Eq(WorkerErrorCode::kErrorReadingSource));
+    ASSERT_THAT(err->Explain(), Eq(hidra2::WorkerErrorMessage::kErrorReadingSource));
 }
 
 
@@ -153,12 +154,11 @@ TEST_F(ServerDataBrokerTests, GetNextCallsReadFromFile) {
     MockGet(json);
 
     EXPECT_CALL(mock_io, GetDataFromFile_t("relative_path/base_name", 100, _)).
-    WillOnce(DoAll(SetArgPointee<2>(IOErrors::kReadError), testing::Return(nullptr)));
+    WillOnce(DoAll(SetArgPointee<2>(new SimpleError{hidra2::IOErrors::kReadError}), testing::Return(nullptr)));
 
     FileData data;
     data_broker->GetNext(&info, &data);
 
 }
 
-
 }
diff --git a/worker/api/cpp/unittests/test_worker_api.cpp b/worker/api/cpp/unittests/test_worker_api.cpp
index 31f67da9f..d555b769f 100644
--- a/worker/api/cpp/unittests/test_worker_api.cpp
+++ b/worker/api/cpp/unittests/test_worker_api.cpp
@@ -3,47 +3,52 @@
 #include "worker/data_broker.h"
 #include "../src/folder_data_broker.h"
 #include "../src/server_data_broker.h"
-
+#include "common/error.h"
 
 using hidra2::DataBrokerFactory;
 using hidra2::DataBroker;
 using hidra2::FolderDataBroker;
 using hidra2::ServerDataBroker;
 
-using hidra2::WorkerErrorCode;
-
+using hidra2::Error;
 using ::testing::Eq;
 using ::testing::Ne;
 using ::testing::Test;
 
 
-
 namespace {
 
-TEST(DataBrokerFactoryTests, CreateFolderDataSource) {
-    WorkerErrorCode return_code;
+class DataBrokerFactoryTests : public Test {
+  public:
+    Error error;
+    void SetUp() override {
+        error.reset(new hidra2::SimpleError("SomeErrorToBeOverwritten"));
+    }
+};
+
+
+TEST_F(DataBrokerFactoryTests, CreateFolderDataSource) {
 
-    auto data_broker = DataBrokerFactory::CreateFolderBroker("path/to/file", &return_code);
+    auto data_broker = DataBrokerFactory::CreateFolderBroker("path/to/file", &error);
 
-    ASSERT_THAT(return_code, Eq(WorkerErrorCode::kOK));
+    ASSERT_THAT(error, Eq(nullptr));
     ASSERT_THAT(dynamic_cast<FolderDataBroker*>(data_broker.get()), Ne(nullptr));
 }
 
-TEST(DataBrokerFactoryTests, FailCreateDataSourceWithEmptySource) {
-    WorkerErrorCode return_code;
+TEST_F(DataBrokerFactoryTests, FailCreateDataSourceWithEmptySource) {
 
-    auto data_broker = DataBrokerFactory::CreateFolderBroker("", &return_code);
+    auto data_broker = DataBrokerFactory::CreateFolderBroker("", &error);
 
-    ASSERT_THAT(return_code, Eq(WorkerErrorCode::kEmptyDatasource));
-    ASSERT_THAT(data_broker.release(), Eq(nullptr));
+//    ASSERT_THAT(error->Explain(), Eq(WorkerErrorMessage::kEmptyDatasource));
+    ASSERT_THAT(error->Explain(), Eq("Empty Data Source"));
+    ASSERT_THAT(data_broker.get(), Eq(nullptr));
 }
 
-TEST(DataBrokerFactoryTests, CreateServerDataSource) {
-    WorkerErrorCode return_code;
+TEST_F(DataBrokerFactoryTests, CreateServerDataSource) {
 
-    auto data_broker = DataBrokerFactory::CreateServerBroker("server", "database", &return_code);
+    auto data_broker = DataBrokerFactory::CreateServerBroker("server", "database", &error);
 
-    ASSERT_THAT(return_code, Eq(WorkerErrorCode::kOK));
+    ASSERT_THAT(error, Eq(nullptr));
     ASSERT_THAT(dynamic_cast<ServerDataBroker*>(data_broker.get()), Ne(nullptr));
 }
 
diff --git a/worker/tools/folder_to_db/src/folder_db_importer.cpp b/worker/tools/folder_to_db/src/folder_db_importer.cpp
index 7ddeab6d3..916f06c10 100644
--- a/worker/tools/folder_to_db/src/folder_db_importer.cpp
+++ b/worker/tools/folder_to_db/src/folder_db_importer.cpp
@@ -11,101 +11,55 @@ namespace hidra2 {
 
 using std::chrono::high_resolution_clock;
 
-
-FolderToDbImportError MapIOError(IOErrors io_err) {
-    FolderToDbImportError err;
-    switch (io_err) {
-    case IOErrors::kNoError:
-        err = FolderToDbImportError::kOK;
-        break;
-    default:
-        err = FolderToDbImportError::kIOError;
-        break;
-        break;
-    }
-    return err;
-}
-
-FolderToDbImportError MapDBError(DBError db_err) {
-    FolderToDbImportError err;
-    switch (db_err) {
-    case DBError::kNoError:
-        err = FolderToDbImportError::kOK;
-        break;
-    case DBError::kConnectionError:
-        err = FolderToDbImportError::kDBConnectionError;
-        break;
-    case DBError::kInsertError:
-    case DBError::kDuplicateID:
-        err = FolderToDbImportError::kImportError;
-        break;
-    case DBError::kMemoryError:
-        err = FolderToDbImportError::kMemoryError;
-        break;
-
-    default:
-        err = FolderToDbImportError::kUnknownDbError;
-        break;
-    }
-    return err;
-}
-
-
 FolderToDbImporter::FolderToDbImporter() :
     io__{new hidra2::SystemIO}, db_factory__{new hidra2::DatabaseFactory} {
 }
 
-FolderToDbImportError FolderToDbImporter::ConnectToDb(const std::unique_ptr<hidra2::Database>& db) const {
-    DBError err = db->Connect(db_uri_, db_name_, kDBCollectionName);
-    return MapDBError(err);
+Error FolderToDbImporter::ConnectToDb(const std::unique_ptr<hidra2::Database>& db) const {
+    return db->Connect(db_uri_, db_name_, kDBCollectionName);
 }
 
-FolderToDbImportError FolderToDbImporter::ImportSingleFile(const std::unique_ptr<hidra2::Database>& db,
-        const FileInfo& file) const {
-
-    auto err = db->Insert(file, ignore_duplicates_);
-    return MapDBError(err);
+Error FolderToDbImporter::ImportSingleFile(const std::unique_ptr<hidra2::Database>& db,
+                                           const FileInfo& file) const {
+    return db->Insert(file, ignore_duplicates_);
 }
 
-FolderToDbImportError FolderToDbImporter::ImportFilelistChunk(const std::unique_ptr<hidra2::Database>& db,
-        const FileInfos& file_list, uint64_t begin, uint64_t end) const {
+Error FolderToDbImporter::ImportFilelistChunk(const std::unique_ptr<hidra2::Database>& db,
+                                              const FileInfos& file_list, uint64_t begin, uint64_t end) const {
     for (auto i = begin; i < end; i++) {
         auto err = ImportSingleFile(db, file_list[i]);
-        if (err != FolderToDbImportError::kOK) {
+        if (err != nullptr) {
             return err;
         }
     }
-    return FolderToDbImportError::kOK;
+    return nullptr;
 }
 
-FolderToDbImportError FolderToDbImporter::PerformParallelTask(const FileInfos& file_list, uint64_t begin,
-        uint64_t end) const {
-    FolderToDbImportError err;
+Error FolderToDbImporter::PerformParallelTask(const FileInfos& file_list, uint64_t begin,
+                                              uint64_t end) const {
+    Error err;
     auto db = CreateDbClient(&err);
-    if (err != FolderToDbImportError::kOK) {
+    if (err) {
         return err;
     }
 
     err = ConnectToDb(db);
-    if (err != FolderToDbImportError::kOK) {
+    if (err) {
         return err;
     }
 
     return ImportFilelistChunk(db, file_list, begin, end);
 }
-std::unique_ptr<hidra2::Database> FolderToDbImporter::CreateDbClient(FolderToDbImportError* err) const {
-    DBError db_err;
-    auto db = db_factory__->Create(&db_err);
-    *err = MapDBError(db_err);
-    return db;
+std::unique_ptr<hidra2::Database> FolderToDbImporter::CreateDbClient(Error* err) const {
+    return db_factory__->Create(err);
 }
 
-FolderToDbImportError WaitParallelTasks(std::vector<std::future<FolderToDbImportError>>* res) {
-    FolderToDbImportError err{FolderToDbImportError::kOK};
+Error WaitParallelTasks(std::vector<std::future<Error>>* res) {
+    Error err{nullptr};
     for (auto& fut : *res) {
         auto task_result = fut.get();
-        if (task_result != FolderToDbImportError::kOK) {
-            err = task_result;
+        if (task_result != nullptr) {
+            err = std::move(task_result);
         }
     }
     return err;
@@ -120,7 +74,7 @@ TaskSplitParameters ComputeSplitParameters(const FileInfos& file_list, int ntask
 }
 
 void FolderToDbImporter::ProcessNextChunk(const FileInfos& file_list,
-                                          std::vector<std::future<FolderToDbImportError>>* res,
+                                          std::vector<std::future<Error>>* res,
                                           TaskSplitParameters* p) const {
     p->next_chunk_size = p->chunk + (p->remainder ? 1 : 0);
     if (p->next_chunk_size == 0) return;
@@ -134,10 +88,10 @@ void FolderToDbImporter::ProcessNextChunk(const FileInfos& file_list,
     if (p->remainder) p->remainder -= 1;
 }
 
-FolderToDbImportError FolderToDbImporter::ImportFilelist(const FileInfos& file_list) const {
+Error FolderToDbImporter::ImportFilelist(const FileInfos& file_list) const {
     auto split_parameters = ComputeSplitParameters(file_list, n_tasks_);
 
-    std::vector<std::future<FolderToDbImportError>>res;
+    std::vector<std::future<Error>>res;
     for (unsigned int i = 0; i < n_tasks_; i++) {
         ProcessNextChunk(file_list, &res, &split_parameters);
     }
@@ -146,24 +100,22 @@ FolderToDbImportError FolderToDbImporter::ImportFilelist(const FileInfos& file_l
 }
 
 
-FileInfos FolderToDbImporter::GetFilesInFolder(const std::string& folder, FolderToDbImportError* err) const {
-    IOErrors err_io;
-    auto file_list = io__->FilesInFolder(folder, &err_io);
-    *err = MapIOError(err_io);
+FileInfos FolderToDbImporter::GetFilesInFolder(const std::string& folder, Error* err) const {
+    auto file_list = io__->FilesInFolder(folder, err);
     return file_list;
 }
 
 
-FolderToDbImportError FolderToDbImporter::Convert(const std::string& uri, const std::string& folder,
-                                                  const std::string& db_name,
-                                                  FolderImportStatistics* statistics) const {
+Error FolderToDbImporter::Convert(const std::string& uri, const std::string& folder,
+                                  const std::string& db_name,
+                                  FolderImportStatistics* statistics) const {
     db_uri_ = uri;
     db_name_ = db_name;
     auto time_begin = high_resolution_clock::now();
 
-    FolderToDbImportError err;
+    Error err;
     auto file_list = GetFilesInFolder(folder, &err);
-    if (err != FolderToDbImportError::kOK) {
+    if (err) {
         return err;
     }
 
@@ -173,7 +125,7 @@ FolderToDbImportError FolderToDbImporter::Convert(const std::string& uri, const
 
     auto time_end_import = high_resolution_clock::now();
 
-    if (err == FolderToDbImportError::kOK && statistics) {
+    if (err == nullptr && statistics) {
         statistics->n_files_converted = file_list.size();
         statistics->time_read_folder = std::chrono::duration_cast<std::chrono::nanoseconds>( time_end_read_folder - time_begin);
         statistics->time_import_files = std::chrono::duration_cast<std::chrono::nanoseconds>
diff --git a/worker/tools/folder_to_db/src/folder_db_importer.h b/worker/tools/folder_to_db/src/folder_db_importer.h
index 4097fd5c9..aecadd203 100644
--- a/worker/tools/folder_to_db/src/folder_db_importer.h
+++ b/worker/tools/folder_to_db/src/folder_db_importer.h
@@ -8,17 +8,17 @@
 
 #include "system_wrappers/io.h"
 #include "database/database.h"
-
+#include "common/error.h"
 namespace hidra2 {
 
-enum class FolderToDbImportError {
-    kOK,
-    kDBConnectionError,
-    kImportError,
-    kIOError,
-    kUnknownDbError,
-    kMemoryError
-};
+namespace FolderToDbImportError {
+
+auto const kDBConnectionError = "DB Connection Error";
+auto const kImportError = "Import Error";
+auto const kUnknownDbError = "Unknown DB Error";
+auto const kMemoryError = "Memory error";
+
+}
 
 struct FolderImportStatistics {
     uint64_t n_files_converted{0};
@@ -40,9 +40,9 @@ class FolderToDbImporter {
 //! Read folder content and write file to the database. We do not optimize
 //! the procedure via bulk write to see the performance of a
 //! single operation (and it is already fast enough)
-    FolderToDbImportError Convert(const std::string& uri, const std::string& folder,
-                                  const std::string& db_name,
-                                  FolderImportStatistics* statistics = nullptr) const;
+    Error Convert(const std::string& uri, const std::string& folder,
+                  const std::string& db_name,
+                  FolderImportStatistics* statistics = nullptr) const;
 
     unsigned int SetNParallelTasks(unsigned int ntasks, bool async = true);
     void IgnoreDuplicates(bool ignore_duplicates = true);
@@ -56,18 +56,18 @@ class FolderToDbImporter {
     bool async_{true};
     mutable std::string db_uri_ ;
     mutable std::string db_name_;
-    FolderToDbImportError ConnectToDb(const std::unique_ptr<hidra2::Database>& db) const;
-    FileInfos GetFilesInFolder(const std::string& folder, FolderToDbImportError* err) const;
-    FolderToDbImportError ImportFilelist(const FileInfos& file_list) const;
-    FolderToDbImportError PerformParallelTask(const FileInfos& file_list, uint64_t begin,
-                                              uint64_t end) const;
-    FolderToDbImportError ImportSingleFile(const std::unique_ptr<hidra2::Database>& db,
-                                           const FileInfo& file) const;
-    FolderToDbImportError ImportFilelistChunk(const std::unique_ptr<hidra2::Database>& db,
-                                              const FileInfos& file_list, uint64_t begin, uint64_t end) const;
+    Error ConnectToDb(const std::unique_ptr<hidra2::Database>& db) const;
+    FileInfos GetFilesInFolder(const std::string& folder, Error* err) const;
+    Error ImportFilelist(const FileInfos& file_list) const;
+    Error PerformParallelTask(const FileInfos& file_list, uint64_t begin,
+                              uint64_t end) const;
+    Error ImportSingleFile(const std::unique_ptr<hidra2::Database>& db,
+                           const FileInfo& file) const;
+    Error ImportFilelistChunk(const std::unique_ptr<hidra2::Database>& db,
+                              const FileInfos& file_list, uint64_t begin, uint64_t end) const;
 
-    std::unique_ptr<Database> CreateDbClient(FolderToDbImportError* err) const;
-    void ProcessNextChunk(const FileInfos& file_list, std::vector<std::future<FolderToDbImportError>>* res,
+    std::unique_ptr<Database> CreateDbClient(Error* err) const;
+    void ProcessNextChunk(const FileInfos& file_list, std::vector<std::future<Error>>* res,
                           TaskSplitParameters* p) const;
 
 };
diff --git a/worker/tools/folder_to_db/src/main.cpp b/worker/tools/folder_to_db/src/main.cpp
index 1d6e3b57b..8e79fed17 100644
--- a/worker/tools/folder_to_db/src/main.cpp
+++ b/worker/tools/folder_to_db/src/main.cpp
@@ -83,7 +83,7 @@ int main(int argc, char* argv[]) {
 
     auto err = importer.Convert(import_params.uri, import_params.folder, import_params.db_name,
                                 &statistics);
-    if (err != hidra2::FolderToDbImportError::kOK) {
+    if (err != nullptr) {
         std::cout << "Error import to database" << std::endl;
         return 1;
     }
diff --git a/worker/tools/folder_to_db/unittests/test_folder_to_db.cpp b/worker/tools/folder_to_db/unittests/test_folder_to_db.cpp
index 28ea39a6f..e7639f043 100644
--- a/worker/tools/folder_to_db/unittests/test_folder_to_db.cpp
+++ b/worker/tools/folder_to_db/unittests/test_folder_to_db.cpp
@@ -27,20 +27,22 @@ using ::testing::Ref;
 using ::testing::Return;
 
 using hidra2::FolderToDbImporter;
-using hidra2::FolderToDbImportError;
 using hidra2::Database;
 using hidra2::DatabaseFactory;
 using hidra2::IO;
-using hidra2::DBError;
-using hidra2::IOErrors;
 using hidra2::kDBCollectionName;
 using hidra2::FileInfos;
 using hidra2::FileInfo;
 using hidra2::MockIO;
+using hidra2::Error;
+using hidra2::TextError;
+using hidra2::SimpleError;
+
 
 
 namespace {
 
+
 TEST(FolderDBConverter, SetCorrectIO) {
     FolderToDbImporter converter{};
     ASSERT_THAT(dynamic_cast<hidra2::SystemIO*>(converter.io__.get()), Ne(nullptr));
@@ -67,10 +69,20 @@ TEST(FolderDBConverter, SetNTasksCorrectly) {
 
 }
 
+
 class MockDatabase : public Database {
   public:
-    MOCK_METHOD3(Connect, DBError (const std::string&, const std::string&, const std::string&));
-    MOCK_CONST_METHOD2(Insert, DBError (const FileInfo&, bool));
+    Error Connect(const std::string& address, const std::string& database,
+                  const std::string& collection ) override {
+        return Error{Connect_t(address, database, collection)};
+
+    }
+    Error Insert(const FileInfo& file, bool ignore_duplicates) const override {
+        return Error{Insert_t(file, ignore_duplicates)};
+    }
+
+    MOCK_METHOD3(Connect_t, SimpleError * (const std::string&, const std::string&, const std::string&));
+    MOCK_CONST_METHOD2(Insert_t, SimpleError * (const FileInfo&, bool));
 
     // stuff to test db destructor is called and avoid "uninteresting call" messages
     MOCK_METHOD0(Die, void());
@@ -89,12 +101,12 @@ class MockDatabaseFactory : public DatabaseFactory {
         for (int i = 0; i < n; i++) {
             auto val = new NiceMock<MockDatabase>;
             db.push_back(val);
-            ON_CALL(*val, Connect(_, _, _))
-            .WillByDefault(Return(DBError::kNoError));
+            ON_CALL(*val, Connect_t(_, _, _))
+            .WillByDefault(Return(nullptr));
         }
     }
-    std::unique_ptr<Database> Create(DBError* err) const noexcept override {
-        *err = DBError::kNoError;
+    std::unique_ptr<Database> Create(Error* err) const noexcept override {
+        *err = nullptr;
         return std::unique_ptr<Database> {db[n++]};
     }
     ~MockDatabaseFactory() {
@@ -105,8 +117,8 @@ class MockDatabaseFactory : public DatabaseFactory {
 };
 
 class FakeDatabaseFactory : public DatabaseFactory {
-    std::unique_ptr<Database> Create(DBError* err) const noexcept override {
-        *err = DBError::kMemoryError;
+    std::unique_ptr<Database> Create(Error* err) const noexcept override {
+        *err = hidra2::TextError(hidra2::DBError::kMemoryError);
         return {};
     }
 };
@@ -141,8 +153,8 @@ class FolderDBConverterTests : public Test {
         folder = "folder";
         db_name = "db_name";
         uri = "db_address";
-        ON_CALL(mock_io, FilesInFolder(_, _)).
-        WillByDefault(DoAll(testing::SetArgPointee<1>(IOErrors::kNoError),
+        ON_CALL(mock_io, FilesInFolder_t(_, _)).
+        WillByDefault(DoAll(testing::SetArgPointee<1>(nullptr),
                             testing::Return(file_infos)));
     }
     void TearDown() override {
@@ -151,26 +163,27 @@ class FolderDBConverterTests : public Test {
 };
 
 
+
 TEST_F(FolderDBConverterTests, ErrorWhenCannotConnect) {
-    EXPECT_CALL(*(mock_dbf->db[0]), Connect(uri, db_name, kDBCollectionName)).
-    WillOnce(testing::Return(DBError::kConnectionError));
+    EXPECT_CALL(*(mock_dbf->db[0]), Connect_t(uri, db_name, kDBCollectionName)).
+    WillOnce(testing::Return(new SimpleError(hidra2::DBError::kConnectionError)));
 
     auto error = converter.Convert(uri, folder, db_name);
-    ASSERT_THAT(error, Eq(FolderToDbImportError::kDBConnectionError));
+    ASSERT_THAT(error, Ne(nullptr));
 }
 
 TEST_F(FolderDBConverterTests, ErrorWhenCannotCreateDbParallel) {
     int nparallel = 3;
-    EXPECT_CALL(*(mock_dbf->db[0]), Connect(uri, _, _)).
-    WillOnce(testing::Return(DBError::kConnectionError));
-    EXPECT_CALL(*(mock_dbf->db[1]), Connect(uri, _, _)).
-    WillOnce(testing::Return(DBError::kConnectionError));
-    EXPECT_CALL(*(mock_dbf->db[2]), Connect(uri, _, _)).
-    WillOnce(testing::Return(DBError::kConnectionError));
+    EXPECT_CALL(*(mock_dbf->db[0]), Connect_t(uri, _, _)).
+    WillOnce(testing::Return(new SimpleError(hidra2::DBError::kConnectionError)));
+    EXPECT_CALL(*(mock_dbf->db[1]), Connect_t(uri, _, _)).
+    WillOnce(testing::Return(new SimpleError(hidra2::DBError::kConnectionError)));
+    EXPECT_CALL(*(mock_dbf->db[2]), Connect_t(uri, _, _)).
+    WillOnce(testing::Return(new SimpleError(hidra2::DBError::kConnectionError)));
 
     converter.SetNParallelTasks(nparallel);
     auto error = converter.Convert(uri, folder, db_name);
-    ASSERT_THAT(error, Eq(FolderToDbImportError::kDBConnectionError));
+    ASSERT_THAT(error, Ne(nullptr));
 }
 
 
@@ -182,31 +195,32 @@ TEST_F(FolderDBConverterTests, DBDestructorCalled) {
 TEST_F(FolderDBConverterTests, ErrorWhenCannotGetFileList) {
 
 
-    EXPECT_CALL(mock_io, FilesInFolder(folder, _)).
-    WillOnce(DoAll(testing::SetArgPointee<1>(IOErrors::kReadError),
+    EXPECT_CALL(mock_io, FilesInFolder_t(folder, _)).
+    WillOnce(DoAll(testing::SetArgPointee<1>(new hidra2::SimpleError("err")),
                    testing::Return(FileInfos {})));
 
     auto error = converter.Convert(uri, folder, db_name);
-    ASSERT_THAT(error, Eq(FolderToDbImportError::kIOError));
+    ASSERT_THAT(error, Ne(nullptr));
 }
 
+
+
 TEST_F(FolderDBConverterTests, PassesIgnoreDuplicates) {
 
-    EXPECT_CALL(*(mock_dbf->db[0]), Insert(_, true));
+    EXPECT_CALL(*(mock_dbf->db[0]), Insert_t(_, true)).Times(3);
 
     converter.IgnoreDuplicates(true);
     converter.Convert(uri, folder, db_name);
 }
 
 
-
 TEST_F(FolderDBConverterTests, ErrorWhenCannotImportFileListToDb) {
 
-    EXPECT_CALL(*(mock_dbf->db[0]), Insert(_, _)).
-    WillOnce(testing::Return(DBError::kInsertError));
+    EXPECT_CALL(*(mock_dbf->db[0]), Insert_t(_, _)).
+    WillOnce(testing::Return(new SimpleError(hidra2::DBError::kInsertError)));
 
     auto error = converter.Convert(uri, folder, db_name);
-    ASSERT_THAT(error, Eq(FolderToDbImportError::kImportError));
+    ASSERT_THAT(error, Ne(nullptr));
 
 }
 // a matcher to compare file_infos (size and basename only) for testing purposes
@@ -221,53 +235,53 @@ MATCHER_P(CompareFileInfo, file, "") {
 TEST_F(FolderDBConverterTests, PassesFileListToInsert) {
 
     for (auto& file : file_infos) {
-        EXPECT_CALL(*(mock_dbf->db[0]), Insert(CompareFileInfo(file), _)).
-        WillOnce(testing::Return(DBError::kNoError));
+        EXPECT_CALL(*(mock_dbf->db[0]), Insert_t(CompareFileInfo(file), _)).
+        WillOnce(testing::Return(nullptr));
     }
 
     auto error = converter.Convert(uri, folder, db_name);
-    ASSERT_THAT(error, Eq(FolderToDbImportError::kOK));
+    ASSERT_THAT(error, Eq(nullptr));
 
 }
 
 TEST_F(FolderDBConverterTests, PassesFileListToInsertInParallel3by3) {
 
-    EXPECT_CALL(*(mock_dbf->db[0]), Insert(CompareFileInfo(file_infos[0]), _)).
-    WillOnce(testing::Return(DBError::kNoError));
-    EXPECT_CALL(*(mock_dbf->db[1]), Insert(CompareFileInfo(file_infos[1]), _)).
-    WillOnce(testing::Return(DBError::kNoError));
-    EXPECT_CALL(*(mock_dbf->db[2]), Insert(CompareFileInfo(file_infos[2]), _)).
-    WillOnce(testing::Return(DBError::kNoError));
+    EXPECT_CALL(*(mock_dbf->db[0]), Insert_t(CompareFileInfo(file_infos[0]), _)).
+    WillOnce(testing::Return(nullptr));
+    EXPECT_CALL(*(mock_dbf->db[1]), Insert_t(CompareFileInfo(file_infos[1]), _)).
+    WillOnce(testing::Return(nullptr));
+    EXPECT_CALL(*(mock_dbf->db[2]), Insert_t(CompareFileInfo(file_infos[2]), _)).
+    WillOnce(testing::Return(nullptr));
 
     converter.SetNParallelTasks(3, false);
     auto error = converter.Convert(uri, folder, db_name);
-    ASSERT_THAT(error, Eq(FolderToDbImportError::kOK));
+    ASSERT_THAT(error, Eq(nullptr));
 }
 
 TEST_F(FolderDBConverterTests, PassesFileListToInsertInParallel3by2) {
 
-    EXPECT_CALL(*(mock_dbf->db[0]), Insert(CompareFileInfo(file_infos[0]), _)).
-    WillOnce(testing::Return(DBError::kNoError));
-    EXPECT_CALL(*(mock_dbf->db[0]), Insert(CompareFileInfo(file_infos[1]), _)).
-    WillOnce(testing::Return(DBError::kNoError));
-    EXPECT_CALL(*(mock_dbf->db[1]), Insert(CompareFileInfo(file_infos[2]), _)).
-    WillOnce(testing::Return(DBError::kNoError));
+    EXPECT_CALL(*(mock_dbf->db[0]), Insert_t(CompareFileInfo(file_infos[0]), _)).
+    WillOnce(testing::Return(nullptr));
+    EXPECT_CALL(*(mock_dbf->db[0]), Insert_t(CompareFileInfo(file_infos[1]), _)).
+    WillOnce(testing::Return(nullptr));
+    EXPECT_CALL(*(mock_dbf->db[1]), Insert_t(CompareFileInfo(file_infos[2]), _)).
+    WillOnce(testing::Return(nullptr));
 
     converter.SetNParallelTasks(2, false);
     auto error = converter.Convert(uri, folder, db_name);
-    ASSERT_THAT(error, Eq(FolderToDbImportError::kOK));
+    ASSERT_THAT(error, Eq(nullptr));
 }
 
 TEST_F(FolderDBConverterTests, ComputesStatistics) {
 
-    EXPECT_CALL(*mock_dbf->db[0], Insert(_, false)).
+    EXPECT_CALL(*mock_dbf->db[0], Insert_t(_, false)).
     Times(file_infos.size()).
-    WillRepeatedly(testing::Return(DBError::kNoError));
+    WillRepeatedly(testing::Return(nullptr));
 
     hidra2::FolderImportStatistics statistics;
     auto error = converter.Convert(uri, folder, db_name, &statistics);
 
-    ASSERT_THAT(error, Eq(FolderToDbImportError::kOK));
+    ASSERT_THAT(error, Eq(nullptr));
     ASSERT_THAT(statistics.n_files_converted, Eq(file_infos.size()));
 // tests may fail is function call is smaller than 1 ns
     ASSERT_THAT(statistics.time_read_folder.count(), Gt(0));
@@ -280,7 +294,7 @@ TEST_F(FolderDBConverterTests, ErrorWhenCannotCreateDB) {
 
     auto err = converter.Convert("", "", "");
 
-    ASSERT_THAT(err, Eq(FolderToDbImportError::kMemoryError));
+    ASSERT_THAT(err, Ne(nullptr));
 
 }
 
-- 
GitLab