From 2329a1e6ac8500a8adbcb326ab402e95efba54ac Mon Sep 17 00:00:00 2001
From: Sergey Yakubov <sergey.yakubov@desy.de>
Date: Fri, 29 Oct 2021 14:47:55 +0200
Subject: [PATCH] refactor errors

---
 .../include/asapo/asapo_fabric/fabric_error.h |   4 +-
 common/cpp/include/asapo/common/error.h       | 197 ++++++------------
 common/cpp/include/asapo/common/io_error.h    |   4 +-
 common/cpp/include/asapo/database/db_error.h  |   4 +-
 .../include/asapo/http_client/http_error.h    |   2 +-
 common/cpp/src/data_structs/data_structs.cpp  |   4 +-
 common/cpp/src/database/database.cpp          |   2 +-
 common/cpp/src/database/mongodb_client.cpp    |   2 +-
 .../cpp/src/http_client/curl_http_client.cpp  |   2 +-
 common/cpp/src/json_parser/rapid_json.cpp     |  14 +-
 common/cpp/src/logger/logger.cpp              |   2 +-
 common/cpp/src/system_io/system_io.cpp        |  10 +-
 .../cpp/src/system_io/system_io_linux_mac.cpp |   2 +-
 common/cpp/unittests/common/test_error.cpp    |  24 ++-
 .../include/asapo/consumer/consumer_error.h   |   2 +-
 consumer/api/cpp/src/consumer.cpp             |   2 +-
 consumer/api/cpp/src/consumer_c_glue.cpp      |   5 +-
 consumer/api/cpp/src/consumer_impl.cpp        |   2 +-
 consumer/api/cpp/src/rds_response_error.h     |   6 +-
 consumer/api/cpp/src/tcp_connection_pool.cpp  |   2 +-
 consumer/api/cpp/src/tcp_consumer_client.cpp  |   2 +-
 .../api/cpp/unittests/test_consumer_api.cpp   |   2 +-
 .../api/cpp/unittests/test_consumer_impl.cpp  |   3 +-
 .../unittests/test_tcp_connection_pool.cpp    |   1 -
 .../unittests/test_tcp_consumer_client.cpp    |   1 -
 .../unittests/test_folder_to_db.cpp           |   4 +-
 .../include/asapo/producer/producer_error.h   |   2 +-
 producer/api/cpp/src/producer.cpp             |   4 +-
 .../cpp/src/receiver_discovery_service.cpp    |   2 +-
 .../src/event_monitor_error.h                 |   2 +-
 .../src/eventmon_config.cpp                   |  11 +-
 .../src/folder_event_detector.cpp             |   2 +-
 .../unittests/test_folder_event_detector.cpp  |   2 +-
 .../net_server/rds_fabric_server.cpp          |   2 +-
 .../net_server/rds_tcp_server.cpp             |   4 +-
 .../receiver_data_server_error.h              |   2 +-
 receiver/src/receiver_error.h                 |   2 +-
 receiver/src/request.cpp                      |   4 +-
 .../request_handler/request_handler_db.cpp    |   7 +-
 .../request_handler/requests_dispatcher.cpp   |   2 +-
 .../net_server/test_rds_tcp_server.cpp        |   2 +-
 .../test_receive_file_processor.cpp           |   4 +-
 .../test_write_file_processor.cpp             |   4 +-
 .../test_authorization_client.cpp             |   2 +-
 .../test_request_handler_db.cpp               |   6 +-
 .../test_request_handler_file_process.cpp     |   4 +-
 .../test_request_handler_receive_data.cpp     |   2 +-
 .../test_requests_dispatcher.cpp              |   4 +-
 receiver/unittests/test_connection.cpp        |   5 +-
 .../client_serv/ip_tcp_network.cpp            |   3 +-
 .../client_serv_multicon/multicon.cpp         |   3 +-
 .../resolve_hostname_to_ip.cpp                |   1 -
 52 files changed, 170 insertions(+), 223 deletions(-)

diff --git a/common/cpp/include/asapo/asapo_fabric/fabric_error.h b/common/cpp/include/asapo/asapo_fabric/fabric_error.h
index 1a8ca0106..95b4e3b14 100644
--- a/common/cpp/include/asapo/asapo_fabric/fabric_error.h
+++ b/common/cpp/include/asapo/asapo_fabric/fabric_error.h
@@ -17,8 +17,8 @@ enum class FabricErrorType {
 };
 
 
-using FabricError = ServiceError<FabricErrorType, ErrorType::kFabricError>;
-using FabricErrorTemplate = ServiceErrorTemplate<FabricErrorType, ErrorType::kFabricError>;
+using FabricError = ServiceError<FabricErrorType>;
+using FabricErrorTemplate = ServiceErrorTemplate<FabricErrorType>;
 
 namespace FabricErrorTemplates {
 auto const kNotSupportedOnBuildError = FabricErrorTemplate {
diff --git a/common/cpp/include/asapo/common/error.h b/common/cpp/include/asapo/common/error.h
index 3366ee7e8..5be9aa106 100644
--- a/common/cpp/include/asapo/common/error.h
+++ b/common/cpp/include/asapo/common/error.h
@@ -7,31 +7,10 @@
 #include <ostream>
 namespace asapo {
 
-enum class ErrorType {
-    kUnknownError = 0,
-    kAsapoError,
-    kHttpError,
-    kIOError,
-    kDBError,
-    kReceiverError,
-    kProducerError,
-    kConsumerError,
-    kMemoryAllocationError,
-    kEndOfFile,
-    kFabricError,
-};
-
 class ErrorInterface;
 class ErrorTemplateInterface;
 class CustomErrorData;
 
-// nullptr == noError
-// Example check:
-//  void TestError(Error* err) {
-//      if(*err) {
-//          [...] //An error occurred
-//      }
-//  }
 using Error = std::unique_ptr<ErrorInterface>;
 
 class ErrorInterface {
@@ -39,39 +18,13 @@ class ErrorInterface {
     virtual std::string Explain() const noexcept = 0;
     virtual void Append(const std::string& value) noexcept = 0;
     virtual void Prepend(const std::string& value) noexcept = 0;
-    virtual ErrorType GetErrorType() const noexcept = 0;
     virtual CustomErrorData* GetCustomData() = 0;
     virtual void SetCustomData(std::unique_ptr<CustomErrorData> data) = 0;
     virtual ~ErrorInterface() = default; // needed for unique_ptr to delete itself
 };
 
-
-class ErrorTemplateInterface {
-  public:
-    virtual ErrorType GetErrorType() const noexcept = 0;
-    virtual Error Generate() const noexcept = 0;
-    virtual Error Generate(const std::string& suffix) const noexcept = 0;
-    virtual std::string Text() const noexcept = 0;
-    virtual inline bool operator == (const Error& rhs) const {
-        return rhs != nullptr &&
-               GetErrorType() == rhs->GetErrorType();
-    }
-
-    virtual inline bool operator != (const Error& rhs) const {
-        return !(operator==(rhs));
-    }
-};
-
-static inline bool operator == (const Error& lhs, const ErrorTemplateInterface& rhs) {
-    return rhs.operator == (lhs);
-}
-
-static inline bool operator != (const Error& lhs, const ErrorTemplateInterface& rhs) {
-    return rhs.operator != (lhs);
-}
-
 static inline std::ostream& operator<<(std::ostream& os, const Error& err) {
-    if(err) {
+    if (err) {
         os << err->Explain();
     } else {
         static std::string no_error = "No error";
@@ -85,18 +38,19 @@ class CustomErrorData {
     virtual ~CustomErrorData() = default;
 };
 
-class SimpleError: public ErrorInterface {
+template<typename ServiceErrorType>
+class ServiceError : public ErrorInterface {
   private:
+    ServiceErrorType error_type_;
     std::string error_;
     std::unique_ptr<CustomErrorData> custom_data_;
-    ErrorType error_type_ = ErrorType::kAsapoError;
   public:
-    explicit SimpleError(std::string error): error_{std::move(error)} {
-
+    ServiceError(const std::string& error, ServiceErrorType error_type) : error_type_{error_type},
+        error_{std::move(error)} {
     }
-    SimpleError(std::string error, ErrorType error_type ): error_{std::move(error)}, error_type_{error_type} {
+    ServiceErrorType GetServiceErrorType() const noexcept {
+        return error_type_;
     }
-
     CustomErrorData* GetCustomData() override {
         if (custom_data_) {
             return custom_data_.get();
@@ -117,116 +71,103 @@ class SimpleError: public ErrorInterface {
         error_ = value + ": " + error_;
     }
 
-    std::string Explain() const noexcept override  {
+    std::string Explain() const noexcept override {
         return error_;
     }
+};
+
+class ErrorTemplateInterface {
+  public:
+    virtual Error Generate() const noexcept = 0;
+    virtual Error Generate(const std::string& suffix) const noexcept = 0;
+
+    virtual inline bool operator==(const Error& rhs) const = 0;
+    virtual inline bool operator!=(const Error& rhs) const = 0;
 
-    ErrorType GetErrorType() const noexcept override  {
-        return error_type_;
-    }
 };
 
+static inline bool operator==(const Error& lhs, const ErrorTemplateInterface& rhs) {
+    return rhs.operator == (lhs);
+}
+
+static inline bool operator!=(const Error& lhs, const ErrorTemplateInterface& rhs) {
+    return rhs.operator != (lhs);
+}
 
-/*
- * IMPORTANT:
- * Never use the same ErrorType for two different errors,
- * otherwise the == operator might not work as expected!
- */
-class SimpleErrorTemplate : public ErrorTemplateInterface {
-  protected:
+template<typename ServiceErrorType>
+class ServiceErrorTemplate : public ErrorTemplateInterface {
+  private:
     std::string error_;
-    ErrorType error_type_ = ErrorType::kAsapoError;
+    ServiceErrorType error_type_;
   public:
-    explicit SimpleErrorTemplate(std::string error): error_{std::move(error)} {
-
+    ServiceErrorTemplate(const std::string& error, ServiceErrorType error_type) {
+        error_ = error;
+        error_type_ = error_type;
     }
 
-    virtual std::string Text() const noexcept override {
+    const std::string& Text() const noexcept {
         return error_;
     }
 
+    ServiceErrorType GetServiceErrorType() const noexcept {
+        return error_type_;
+    }
 
-    SimpleErrorTemplate(std::string error, ErrorType error_type ): error_{std::move(error)}, error_type_{error_type} {
+    Error Generate() const noexcept {
+        auto err = new ServiceError<ServiceErrorType>(error_, error_type_);
+        return Error(err);
     }
 
-    inline ErrorType GetErrorType() const noexcept override {
-        return error_type_;
+    Error Generate(const std::string& suffix) const noexcept {
+        return Error(new ServiceError<ServiceErrorType>(error_ + (error_.empty() ? "" : ": ") + suffix, error_type_));
     }
 
-    inline Error Generate() const noexcept override {
-        return Error(new SimpleError{error_, error_type_});
+    inline bool operator==(const Error& rhs) const {
+        return rhs != nullptr
+               && GetServiceErrorType() == ((ServiceError<ServiceErrorType>*) rhs.get())->GetServiceErrorType();
     }
 
-    inline Error Generate(const std::string& suffix) const noexcept override {
-        return Error(new SimpleError{error_ + " :" + suffix, error_type_});
+    inline bool operator!=(const Error& rhs) const {
+        return rhs != nullptr
+               && GetServiceErrorType() != ((ServiceError<ServiceErrorType>*) rhs.get())->GetServiceErrorType();
     }
 
 };
 
-static inline std::ostream& operator<<(std::ostream& os, const SimpleErrorTemplate& err) {
-    return os << err.Text();
+template<typename ServiceErrorType>
+static inline bool operator==(const Error& lhs, const ServiceErrorTemplate<ServiceErrorType>& rhs) {
+    return rhs.operator == (lhs);
 }
 
-
-inline Error TextError(const std::string& error) {
-    return Error{new SimpleError{error}};
+template<typename ServiceErrorType>
+static inline bool operator!=(const Error& lhs, const ServiceErrorTemplate<ServiceErrorType>& rhs) {
+    return rhs.operator != (lhs);
 }
 
-inline Error TextErrorWithType(const std::string& error, ErrorType error_type) {
-    return Error{new SimpleError{error, error_type}};
-}
+namespace GeneralErrorTemplates {
 
-namespace ErrorTemplates {
-auto const kMemoryAllocationError = SimpleErrorTemplate {
-    "kMemoryAllocationError", ErrorType::kMemoryAllocationError
-};
-auto const kEndOfFile = SimpleErrorTemplate {
-    "End of file", ErrorType::kEndOfFile
+enum class GeneralErrorType {
+    kMemoryAllocationError,
+    kEndOfFile,
+    kSimpleError,
 };
 
-}
+using GeneralError = ServiceError<GeneralErrorType>;
+using GeneralErrorTemplate = ServiceErrorTemplate<GeneralErrorType>;
 
-template <typename ServiceErrorType, ErrorType MainErrorType>
-class ServiceError : public SimpleError {
-  private:
-    ServiceErrorType error_type_;
-  public:
-    ServiceError(const std::string& error, ServiceErrorType error_type) : SimpleError(error, MainErrorType) {
-        error_type_ = error_type;
-    }
-    ServiceErrorType GetServiceErrorType() const noexcept {
-        return error_type_;
-    }
+auto const kMemoryAllocationError = GeneralErrorTemplate {
+    "kMemoryAllocationError", GeneralErrorType::kMemoryAllocationError
 };
 
-template <typename ServiceErrorType, ErrorType MainErrorType>
-class ServiceErrorTemplate : public SimpleErrorTemplate {
-  protected:
-    ServiceErrorType error_type_;
-  public:
-    ServiceErrorTemplate(const std::string& error, ServiceErrorType error_type) : SimpleErrorTemplate(error,
-                MainErrorType) {
-        error_type_ = error_type;
-    }
-
-    inline ServiceErrorType GetServiceErrorType() const noexcept {
-        return error_type_;
-    }
-
-    inline Error Generate() const noexcept override {
-        auto err = new ServiceError<ServiceErrorType, MainErrorType>(error_, error_type_);
-        return Error(err);
-    }
-
-    inline Error Generate(const std::string& suffix) const noexcept override {
-        return Error(new ServiceError<ServiceErrorType, MainErrorType>(error_ + ": " + suffix, error_type_));
-    }
+auto const kEndOfFile = GeneralErrorTemplate {
+    "End of file", GeneralErrorType::kEndOfFile
+};
 
-    inline bool operator==(const Error& rhs) const override {
-        return SimpleErrorTemplate::operator==(rhs)
-               && GetServiceErrorType() == ((ServiceError<ServiceErrorType, MainErrorType>*) rhs.get())->GetServiceErrorType();
-    }
+auto const kSimpleError = GeneralErrorTemplate {
+    "", GeneralErrorType::kSimpleError
 };
 
+}
+
 }
 #endif //ASAPO_ERROR_H
diff --git a/common/cpp/include/asapo/common/io_error.h b/common/cpp/include/asapo/common/io_error.h
index e11399e00..ef15e6308 100644
--- a/common/cpp/include/asapo/common/io_error.h
+++ b/common/cpp/include/asapo/common/io_error.h
@@ -31,8 +31,8 @@ enum class IOErrorType {
     kNotConnected
 };
 
-using IOError = ServiceError<IOErrorType, ErrorType::kIOError>;
-using IOErrorTemplate = ServiceErrorTemplate<IOErrorType, ErrorType::kIOError>;
+using IOError = ServiceError<IOErrorType>;
+using IOErrorTemplate = ServiceErrorTemplate<IOErrorType>;
 
 namespace IOErrorTemplates {
 auto const kUnknownIOError = IOErrorTemplate {
diff --git a/common/cpp/include/asapo/database/db_error.h b/common/cpp/include/asapo/database/db_error.h
index 6128dcbbd..aa16a143f 100644
--- a/common/cpp/include/asapo/database/db_error.h
+++ b/common/cpp/include/asapo/database/db_error.h
@@ -20,8 +20,8 @@ enum class DBErrorType {
     kWrongInput
 };
 
-using DBError = ServiceError<DBErrorType, ErrorType::kDBError>;
-using DBErrorTemplate = ServiceErrorTemplate<DBErrorType, ErrorType::kDBError>;
+using DBError = ServiceError<DBErrorType>;
+using DBErrorTemplate = ServiceErrorTemplate<DBErrorType>;
 
 namespace DBErrorTemplates {
 
diff --git a/common/cpp/include/asapo/http_client/http_error.h b/common/cpp/include/asapo/http_client/http_error.h
index b701cb31d..a52af7bfb 100644
--- a/common/cpp/include/asapo/http_client/http_error.h
+++ b/common/cpp/include/asapo/http_client/http_error.h
@@ -11,7 +11,7 @@ enum class HttpErrorType {
     kConnectionError
 };
 
-using HttpErrorTemplate = ServiceErrorTemplate<HttpErrorType, ErrorType::kHttpError>;
+using HttpErrorTemplate = ServiceErrorTemplate<HttpErrorType>;
 
 namespace HttpErrorTemplates {
 
diff --git a/common/cpp/src/data_structs/data_structs.cpp b/common/cpp/src/data_structs/data_structs.cpp
index ae9712325..0e1562ea7 100644
--- a/common/cpp/src/data_structs/data_structs.cpp
+++ b/common/cpp/src/data_structs/data_structs.cpp
@@ -1,4 +1,6 @@
 #include "asapo/common/data_structs.h"
+#include "asapo/common/error.h"
+
 
 #include <chrono>
 #include <iostream>
@@ -40,7 +42,7 @@ Error GetSourceTypeFromString(std::string stype, SourceType* type) {
         *type = SourceType::kProcessed;
         return nullptr;
     } else {
-        return TextError("cannot parse/wrong source type: " + stype);
+        return GeneralErrorTemplates::kSimpleError.Generate("cannot parse/wrong source type: " + stype);
     }
 }
 
diff --git a/common/cpp/src/database/database.cpp b/common/cpp/src/database/database.cpp
index df1c69ea3..6ad05bb96 100644
--- a/common/cpp/src/database/database.cpp
+++ b/common/cpp/src/database/database.cpp
@@ -9,7 +9,7 @@ std::unique_ptr<Database> DatabaseFactory::Create(Error* err) const noexcept {
         p.reset(new MongoDBClient());
         *err = nullptr;
     } catch (...) {
-        *err = ErrorTemplates::kMemoryAllocationError.Generate();
+        *err = GeneralErrorTemplates::kMemoryAllocationError.Generate();
     }
     return p;
 }
diff --git a/common/cpp/src/database/mongodb_client.cpp b/common/cpp/src/database/mongodb_client.cpp
index f9813a686..50db4ae16 100644
--- a/common/cpp/src/database/mongodb_client.cpp
+++ b/common/cpp/src/database/mongodb_client.cpp
@@ -180,7 +180,7 @@ bson_p PrepareUpdateDocument(const uint8_t* json, Error* err) {
 bson_p PrepareInjestDocument(const uint8_t* json, ssize_t len, Error* err) {
     bson_error_t mongo_err;
     if (json == nullptr) {
-        *err = TextError("empty metadata");
+        *err = GeneralErrorTemplates::kSimpleError.Generate("empty metadata");
         return nullptr;
     }
 
diff --git a/common/cpp/src/http_client/curl_http_client.cpp b/common/cpp/src/http_client/curl_http_client.cpp
index 6eed5c457..6ee5dba35 100644
--- a/common/cpp/src/http_client/curl_http_client.cpp
+++ b/common/cpp/src/http_client/curl_http_client.cpp
@@ -113,7 +113,7 @@ MessageData AllocateMemory(uint64_t size, Error* err) {
     try {
         data = MessageData{new uint8_t[(size_t)size + 1 ]};
     } catch (...) {
-        *err = ErrorTemplates::kMemoryAllocationError.Generate();
+        *err = GeneralErrorTemplates::kMemoryAllocationError.Generate();
         return nullptr;
     }
     *err = nullptr;
diff --git a/common/cpp/src/json_parser/rapid_json.cpp b/common/cpp/src/json_parser/rapid_json.cpp
index c21fa0f27..a9883d134 100644
--- a/common/cpp/src/json_parser/rapid_json.cpp
+++ b/common/cpp/src/json_parser/rapid_json.cpp
@@ -14,7 +14,7 @@ RapidJson::RapidJson(const std::string& json, const std::unique_ptr<IO>* io) : i
 
 Error RapidJson::LazyInitialize() const noexcept {
     if (embedded_error_) {
-        return TextError(embedded_error_->Explain());
+        return GeneralErrorTemplates::kSimpleError.Generate(embedded_error_->Explain());
     }
 
     if (initialized_)
@@ -31,7 +31,7 @@ Error RapidJson::LazyInitialize() const noexcept {
 
     ParseResult ok = doc_.Parse(str.c_str());
     if (!ok || !doc_.IsObject()) {
-        return TextError("Cannot parse document");
+        return GeneralErrorTemplates::kSimpleError.Generate("Cannot parse document");
     }
 
     object_ = doc_.GetObject();
@@ -66,7 +66,7 @@ asapo::Error RapidJson::CheckValueType(const std::string& name, ValueType type,
         res = false;
     }
     if (!res) {
-        return TextError("wrong type for: " + name + " in: " + json_);
+        return GeneralErrorTemplates::kSimpleError.Generate("wrong type for: " + name + " in: " + json_);
     }
 
     return nullptr;
@@ -79,7 +79,7 @@ asapo::Error RapidJson::GetValuePointer(const std::string& name, ValueType type,
 
     auto iterator = object_p_->FindMember(name.c_str());
     if (iterator == object_p_->MemberEnd()) {
-        return TextError("cannot find: " + name);
+        return GeneralErrorTemplates::kSimpleError.Generate("cannot find: " + name);
     }
 
     *val = &iterator->value;
@@ -143,7 +143,7 @@ Error RapidJson::GetArrayUInt64(const std::string& name, std::vector<uint64_t>*
     val->clear();
     for (auto& v : json_val->GetArray()) {
         if (!v.IsUint64()) {
-            return TextError("wrong type of array element: " + name);
+            return GeneralErrorTemplates::kSimpleError.Generate("wrong type of array element: " + name);
         }
         val->push_back(v.GetUint64());
     }
@@ -160,7 +160,7 @@ Error RapidJson::GetArrayString(const std::string& name, std::vector<std::string
     val->clear();
     for (auto& v : json_val->GetArray()) {
         if (!v.IsString()) {
-            return TextError("wrong type of array element: " + name);
+            return GeneralErrorTemplates::kSimpleError.Generate("wrong type of array element: " + name);
         }
         val->push_back(v.GetString());
     }
@@ -202,7 +202,7 @@ Error RapidJson::GetArrayRawStrings(const std::string& name, std::vector<std::st
     val->clear();
     for (auto& v : json_val->GetArray()) {
         if (!v.IsObject()) {
-            return TextError("wrong type of array element: " + name);
+            return GeneralErrorTemplates::kSimpleError.Generate("wrong type of array element: " + name);
         }
         StringBuffer buffer;
         Writer<StringBuffer> writer(buffer);
diff --git a/common/cpp/src/logger/logger.cpp b/common/cpp/src/logger/logger.cpp
index 6cb0fbe7c..bd474fb53 100644
--- a/common/cpp/src/logger/logger.cpp
+++ b/common/cpp/src/logger/logger.cpp
@@ -35,7 +35,7 @@ LogLevel StringToLogLevel(const std::string& name, Error* err) {
     if (name == "none") return LogLevel::None;
     if (name == "error") return LogLevel::Error;
 
-    *err = TextError("wrong log level: " + name);
+    *err = GeneralErrorTemplates::kSimpleError.Generate("wrong log level: " + name);
     return LogLevel::None;
 }
 
diff --git a/common/cpp/src/system_io/system_io.cpp b/common/cpp/src/system_io/system_io.cpp
index 6b35e0491..55908b574 100644
--- a/common/cpp/src/system_io/system_io.cpp
+++ b/common/cpp/src/system_io/system_io.cpp
@@ -85,7 +85,7 @@ uint8_t* SystemIO::AllocateArray(uint64_t fsize, Error* err) const {
     try {
         data_array = new uint8_t[(size_t)fsize];
     } catch (...) {
-        *err = ErrorTemplates::kMemoryAllocationError.Generate();
+        *err = GeneralErrorTemplates::kMemoryAllocationError.Generate();
         return nullptr;
     }
     return data_array;
@@ -238,7 +238,7 @@ void SystemIO::Skip(SocketDescriptor socket_fd, size_t length, Error* err) const
     try {
         buffer.reset(new uint8_t[kSkipBufferSize]);
     } catch (...) {
-        *err = ErrorTemplates::kMemoryAllocationError.Generate();
+        *err = GeneralErrorTemplates::kMemoryAllocationError.Generate();
         return;
     }
     size_t already_skipped = 0;
@@ -585,7 +585,7 @@ size_t SystemIO::Transfer(ssize_t (* method)(FileDescriptor, void*, size_t), Fil
         ssize_t received_amount = method(fd, (uint8_t*) buf + already_transferred,
                                          std::min(kMaxTransferChunkSize, length - already_transferred));
         if (received_amount == 0) {
-            *err = ErrorTemplates::kEndOfFile.Generate();
+            *err = GeneralErrorTemplates::kEndOfFile.Generate();
             return already_transferred;
         }
         if (received_amount == -1) {
@@ -665,7 +665,7 @@ Error SystemIO::SendFile(SocketDescriptor socket_fd, const std::string& fname, s
 
     while (total_bytes_sent < length) {
         auto bytes_read = Read(fd, data_array.get(), buf_size, &err);
-        if (err != nullptr && err != ErrorTemplates::kEndOfFile) {
+        if (err != nullptr && err != GeneralErrorTemplates::kEndOfFile) {
             Close(fd, nullptr);
             return err;
         }
@@ -698,7 +698,7 @@ Error SystemIO:: ReceiveDataToFile(SocketDescriptor socket, const std::string& r
     size_t total_bytes_written = 0;
     while (total_bytes_written < length) {
         auto bytes_received = Receive(socket, data_array.get(), std::min(buf_size, length - total_bytes_written), &err);
-        if (err != nullptr && err != ErrorTemplates::kEndOfFile) {
+        if (err != nullptr && err != GeneralErrorTemplates::kEndOfFile) {
             Close(fd, nullptr);
             return err;
         }
diff --git a/common/cpp/src/system_io/system_io_linux_mac.cpp b/common/cpp/src/system_io/system_io_linux_mac.cpp
index 9d36dca7b..819c6d2d0 100644
--- a/common/cpp/src/system_io/system_io_linux_mac.cpp
+++ b/common/cpp/src/system_io/system_io_linux_mac.cpp
@@ -32,7 +32,7 @@ Error GetLastErrorFromErrno() {
     case 0:
         return nullptr;
     case EINTR:
-        return TextError("Interrupt occurred, is a debugger attached?");
+        return GeneralErrorTemplates::kSimpleError.Generate("Interrupt occurred, is a debugger attached?");
     case EBADF:
         return IOErrorTemplates::kBadFileNumber.Generate();
     case EAGAIN:
diff --git a/common/cpp/unittests/common/test_error.cpp b/common/cpp/unittests/common/test_error.cpp
index 73f025bc2..224c890c8 100644
--- a/common/cpp/unittests/common/test_error.cpp
+++ b/common/cpp/unittests/common/test_error.cpp
@@ -3,24 +3,34 @@
 #include "gtest/gtest.h"
 
 using asapo::Error;
-using ::testing::Eq;
-using ::testing::Ne;
+using namespace testing;
 
 namespace {
 
 TEST(ErrorTemplate, GenerateNoNullptr) {
-    Error error = asapo::ErrorTemplates::kEndOfFile.Generate();
+    Error error = asapo::GeneralErrorTemplates::kEndOfFile.Generate();
     ASSERT_THAT(error, Ne(nullptr));
 }
 
 TEST(ErrorTemplate, EqCheck) {
-    Error error = asapo::ErrorTemplates::kEndOfFile.Generate();
-    ASSERT_TRUE(asapo::ErrorTemplates::kEndOfFile == error);
+    Error error = asapo::GeneralErrorTemplates::kEndOfFile.Generate();
+    ASSERT_TRUE(asapo::GeneralErrorTemplates::kEndOfFile == error);
 }
 
 
 TEST(ErrorTemplate, NeCheck) {
-    Error error = asapo::ErrorTemplates::kEndOfFile.Generate();
-    ASSERT_FALSE(asapo::ErrorTemplates::kMemoryAllocationError == error);
+    Error error = asapo::GeneralErrorTemplates::kEndOfFile.Generate();
+    ASSERT_FALSE(asapo::GeneralErrorTemplates::kMemoryAllocationError == error);
 }
+
+TEST(ErrorTemplate, Explain) {
+    Error error = asapo::GeneralErrorTemplates::kEndOfFile.Generate("test");
+    ASSERT_THAT(error->Explain(), HasSubstr("test"));
+}
+
+TEST(ErrorTemplate, Append) {
+    Error error = asapo::GeneralErrorTemplates::kEndOfFile.Generate("test");
+    ASSERT_THAT(error->Explain(), HasSubstr("test2"));
+}
+
 }
diff --git a/consumer/api/cpp/include/asapo/consumer/consumer_error.h b/consumer/api/cpp/include/asapo/consumer/consumer_error.h
index efa0631da..e524e1c1e 100644
--- a/consumer/api/cpp/include/asapo/consumer/consumer_error.h
+++ b/consumer/api/cpp/include/asapo/consumer/consumer_error.h
@@ -18,7 +18,7 @@ enum class ConsumerErrorType {
     kUnsupportedClient
 };
 
-using ConsumerErrorTemplate = ServiceErrorTemplate<ConsumerErrorType, ErrorType::kConsumerError>;
+using ConsumerErrorTemplate = ServiceErrorTemplate<ConsumerErrorType>;
 
 
 class PartialErrorData : public CustomErrorData {
diff --git a/consumer/api/cpp/src/consumer.cpp b/consumer/api/cpp/src/consumer.cpp
index cb7e6bc16..ea1fa64a9 100644
--- a/consumer/api/cpp/src/consumer.cpp
+++ b/consumer/api/cpp/src/consumer.cpp
@@ -19,7 +19,7 @@ std::unique_ptr<Consumer> Create(const std::string& source_name,
         p.reset(new C(source_name, std::forward<Args>(args)...));
         error->reset(nullptr);
     } catch (...) {         // we do not test this part
-        error->reset(new SimpleError("Memory error"));
+        *error = asapo::GeneralErrorTemplates::kMemoryAllocationError.Generate();
     }
 
     return p;
diff --git a/consumer/api/cpp/src/consumer_c_glue.cpp b/consumer/api/cpp/src/consumer_c_glue.cpp
index 392cd837d..267110603 100644
--- a/consumer/api/cpp/src/consumer_c_glue.cpp
+++ b/consumer/api/cpp/src/consumer_c_glue.cpp
@@ -80,7 +80,7 @@ extern "C" {
                   kWrongInput == asapo::ConsumerErrorType::kWrongInput&&
                   kPartialData == asapo::ConsumerErrorType::kPartialData&&
                   kUnsupportedClient == asapo::ConsumerErrorType::kUnsupportedClient,
-                  "incompatible bit reps between c++ and c for asapo::ErrorType");
+                  "incompatible bit reps between c++ and c for asapo::ConsumerErrorType");
     static_assert(kAllStreams == asapo::StreamFilter::kAllStreams&&
                   kFinishedStreams == asapo::StreamFilter::kFinishedStreams&&
                   kUnfinishedStreams == asapo::StreamFilter::kUnfinishedStreams,
@@ -92,8 +92,7 @@ extern "C" {
 
     enum AsapoConsumerErrorType asapo_error_get_type(const AsapoErrorHandle error) {
         auto consumer_err =
-            dynamic_cast<const asapo::ServiceError<asapo::ConsumerErrorType,
-            asapo::ErrorType::kConsumerError> *>(error->handle.get());
+            dynamic_cast<const asapo::ServiceError<asapo::ConsumerErrorType> *>(error->handle.get());
         if (consumer_err != nullptr) {
             return static_cast<AsapoConsumerErrorType>(consumer_err->GetServiceErrorType());
         } else {
diff --git a/consumer/api/cpp/src/consumer_impl.cpp b/consumer/api/cpp/src/consumer_impl.cpp
index 02cd9b981..738434f7b 100644
--- a/consumer/api/cpp/src/consumer_impl.cpp
+++ b/consumer/api/cpp/src/consumer_impl.cpp
@@ -740,7 +740,7 @@ StreamInfos ParseStreamsFromResponse(std::string response, Error* err) {
         StreamInfo si;
         auto ok = si.SetFromJson(stream_encoded);
         if (!ok) {
-            *err = TextError("cannot parse " + stream_encoded);
+            *err = GeneralErrorTemplates::kSimpleError.Generate("cannot parse " + stream_encoded);
             return StreamInfos{};
         }
         streams.emplace_back(si);
diff --git a/consumer/api/cpp/src/rds_response_error.h b/consumer/api/cpp/src/rds_response_error.h
index 8bc8d64c5..27565d8c3 100644
--- a/consumer/api/cpp/src/rds_response_error.h
+++ b/consumer/api/cpp/src/rds_response_error.h
@@ -5,8 +5,8 @@
 
 namespace asapo {
 
-using RdsResponseError = ServiceError<NetworkErrorCode, ErrorType::kFabricError>;
-using RdsResponseErrorTemplate = ServiceErrorTemplate<NetworkErrorCode, ErrorType::kFabricError>;
+using RdsResponseError = ServiceError<NetworkErrorCode>;
+using RdsResponseErrorTemplate = ServiceErrorTemplate<NetworkErrorCode>;
 
 namespace RdsResponseErrorTemplates {
 auto const kNetErrorReauthorize = RdsResponseErrorTemplate {
@@ -53,7 +53,7 @@ inline Error ConvertRdsResponseToError(NetworkErrorCode error_code) {
     case kNetErrorInternalServerError:
         return RdsResponseErrorTemplates::kNetErrorInternalServerError.Generate();
     default:
-        return TextError("Unknown RDS response code " + std::to_string(error_code));
+        return GeneralErrorTemplates::kSimpleError.Generate("Unknown RDS response code " + std::to_string(error_code));
     }
 }
 }
diff --git a/consumer/api/cpp/src/tcp_connection_pool.cpp b/consumer/api/cpp/src/tcp_connection_pool.cpp
index 40407b89a..38bc9a762 100644
--- a/consumer/api/cpp/src/tcp_connection_pool.cpp
+++ b/consumer/api/cpp/src/tcp_connection_pool.cpp
@@ -55,7 +55,7 @@ SocketDescriptor TcpConnectionPool::Reconnect(SocketDescriptor sd, Error* err) {
         }
     }
 
-    *err = Error{new SimpleError("cannot find connection in pool")};
+    *err = asapo::GeneralErrorTemplates::kSimpleError.Generate("cannot find connection in pool");
     return kDisconnectedSocketDescriptor;
 }
 
diff --git a/consumer/api/cpp/src/tcp_consumer_client.cpp b/consumer/api/cpp/src/tcp_consumer_client.cpp
index 11ea5626f..2f5ea5396 100644
--- a/consumer/api/cpp/src/tcp_consumer_client.cpp
+++ b/consumer/api/cpp/src/tcp_consumer_client.cpp
@@ -85,7 +85,7 @@ Error TcpConsumerClient::ReceiveData(SocketDescriptor sd, const MessageMeta* inf
         data_array = new uint8_t[(size_t)info->size];
     } catch (...) {
         connection_pool__->ReleaseConnection(sd);
-        return ErrorTemplates::kMemoryAllocationError.Generate();
+        return GeneralErrorTemplates::kMemoryAllocationError.Generate();
     }
     io__->Receive(sd, data_array, (size_t)info->size, &err);
     connection_pool__->ReleaseConnection(sd);
diff --git a/consumer/api/cpp/unittests/test_consumer_api.cpp b/consumer/api/cpp/unittests/test_consumer_api.cpp
index f9d0a0cf2..c96b73821 100644
--- a/consumer/api/cpp/unittests/test_consumer_api.cpp
+++ b/consumer/api/cpp/unittests/test_consumer_api.cpp
@@ -20,7 +20,7 @@ class ConsumerFactoryTests : public Test {
   public:
     Error error;
     void SetUp() override {
-        error.reset(new asapo::SimpleError("SomeErrorToBeOverwritten"));
+        error = asapo::GeneralErrorTemplates::kSimpleError.Generate("SomeErrorToBeOverwritten");
     }
 };
 
diff --git a/consumer/api/cpp/unittests/test_consumer_impl.cpp b/consumer/api/cpp/unittests/test_consumer_impl.cpp
index ef3ea07bf..ed8e8b075 100644
--- a/consumer/api/cpp/unittests/test_consumer_impl.cpp
+++ b/consumer/api/cpp/unittests/test_consumer_impl.cpp
@@ -26,7 +26,6 @@ using asapo::MockIO;
 using asapo::MockHttpClient;
 using asapo::MockNetClient;
 using asapo::HttpCode;
-using asapo::SimpleError;
 
 using ::testing::AtLeast;
 using ::testing::Eq;
@@ -183,7 +182,7 @@ class ConsumerImplTests : public Test {
         }
 
         auto simple_error = [] {
-            return new asapo::SimpleError{"s"};
+            return asapo::GeneralErrorTemplates::kSimpleError.Generate("s").release();
         };
 
         EXPECT_CALL(mock_io, GetDataFromFile_t(expected_full_path, testing::Pointee(100), _)).Times(AtLeast(times)).
diff --git a/consumer/api/cpp/unittests/test_tcp_connection_pool.cpp b/consumer/api/cpp/unittests/test_tcp_connection_pool.cpp
index 74f3990df..d8e3f9f36 100644
--- a/consumer/api/cpp/unittests/test_tcp_connection_pool.cpp
+++ b/consumer/api/cpp/unittests/test_tcp_connection_pool.cpp
@@ -12,7 +12,6 @@ using asapo::IO;
 using asapo::MessageMeta;
 using asapo::MessageData;
 using asapo::MockIO;
-using asapo::SimpleError;
 using asapo::TcpConnectionPool;
 using asapo::SocketDescriptor;
 using asapo::Error;
diff --git a/consumer/api/cpp/unittests/test_tcp_consumer_client.cpp b/consumer/api/cpp/unittests/test_tcp_consumer_client.cpp
index a17255045..7ae50313b 100644
--- a/consumer/api/cpp/unittests/test_tcp_consumer_client.cpp
+++ b/consumer/api/cpp/unittests/test_tcp_consumer_client.cpp
@@ -12,7 +12,6 @@ using asapo::IO;
 using asapo::MessageMeta;
 using asapo::MessageData;
 using asapo::MockIO;
-using asapo::SimpleError;
 using asapo::TcpConsumerClient;
 using asapo::MockTCPConnectionPool;
 
diff --git a/consumer/tools/folder_to_db/unittests/test_folder_to_db.cpp b/consumer/tools/folder_to_db/unittests/test_folder_to_db.cpp
index cee9a314d..ae1e11939 100644
--- a/consumer/tools/folder_to_db/unittests/test_folder_to_db.cpp
+++ b/consumer/tools/folder_to_db/unittests/test_folder_to_db.cpp
@@ -90,7 +90,7 @@ class MockDatabaseFactory : public DatabaseFactory {
 
 class FakeDatabaseFactory : public DatabaseFactory {
     std::unique_ptr<Database> Create(Error* err) const noexcept override {
-        *err = asapo::ErrorTemplates::kMemoryAllocationError.Generate();
+        *err = asapo::GeneralErrorTemplates::kMemoryAllocationError.Generate();
         return {};
     }
 };
@@ -166,7 +166,7 @@ TEST_F(FolderDBConverterTests, ErrorWhenCannotGetFileList) {
 
 
     EXPECT_CALL(mock_io, FilesInFolder_t(folder, _)).
-    WillOnce(DoAll(testing::SetArgPointee<1>(new asapo::SimpleError("err")),
+    WillOnce(DoAll(testing::SetArgPointee<1>(asapo::GeneralErrorTemplates::kSimpleError.Generate("err").release()),
                    testing::Return(MessageMetas {})));
 
     auto error = converter.Convert(uri, folder, db_name);
diff --git a/producer/api/cpp/include/asapo/producer/producer_error.h b/producer/api/cpp/include/asapo/producer/producer_error.h
index 7b6bc174d..e73e113ae 100644
--- a/producer/api/cpp/include/asapo/producer/producer_error.h
+++ b/producer/api/cpp/include/asapo/producer/producer_error.h
@@ -17,7 +17,7 @@ enum class ProducerErrorType {
     kTimeout
 };
 
-using ProducerErrorTemplate = ServiceErrorTemplate<ProducerErrorType, ErrorType::kProducerError>;
+using ProducerErrorTemplate = ServiceErrorTemplate<ProducerErrorType>;
 
 class OriginalData : public CustomErrorData {
   public:
diff --git a/producer/api/cpp/src/producer.cpp b/producer/api/cpp/src/producer.cpp
index 3c277fcfe..a437fcc56 100644
--- a/producer/api/cpp/src/producer.cpp
+++ b/producer/api/cpp/src/producer.cpp
@@ -15,10 +15,10 @@ std::unique_ptr<asapo::Producer> asapo::Producer::Create(const std::string& endp
     try {
         producer.reset(new ProducerImpl(endpoint, n_processing_threads, timeout_ms, type));
     } catch (const std::exception& ex) {
-        *err = TextError(ex.what());
+        *err = GeneralErrorTemplates::kSimpleError.Generate(ex.what());
         return nullptr;
     } catch (...) {
-        *err = TextError("Unknown exception in producer_api ");
+        *err = GeneralErrorTemplates::kSimpleError.Generate("Unknown exception in producer_api ");
         return nullptr;
     }
 
diff --git a/producer/api/cpp/src/receiver_discovery_service.cpp b/producer/api/cpp/src/receiver_discovery_service.cpp
index 33af1acde..45e7c4195 100644
--- a/producer/api/cpp/src/receiver_discovery_service.cpp
+++ b/producer/api/cpp/src/receiver_discovery_service.cpp
@@ -46,7 +46,7 @@ Error ReceiverDiscoveryService::UpdateFromEndpoint(ReceiversList* list, uint64_t
         return err;
     }
     if (code != HttpCode::OK) {
-        return TextError(responce);
+        return GeneralErrorTemplates::kSimpleError.Generate(responce);
     }
     return ParseResponse(responce, list, max_connections);
 
diff --git a/producer/event_monitor_producer/src/event_monitor_error.h b/producer/event_monitor_producer/src/event_monitor_error.h
index f3dcf37cc..3ed7c91cf 100644
--- a/producer/event_monitor_producer/src/event_monitor_error.h
+++ b/producer/event_monitor_producer/src/event_monitor_error.h
@@ -10,7 +10,7 @@ enum class EventMonitorErrorType {
     kSystemError
 };
 
-using EventMonitorErrorTemplate = ServiceErrorTemplate<EventMonitorErrorType, ErrorType::kAsapoError>;
+using EventMonitorErrorTemplate = ServiceErrorTemplate<EventMonitorErrorType>;
 
 namespace EventMonitorErrorTemplates {
 auto const kNoNewEvent = EventMonitorErrorTemplate {
diff --git a/producer/event_monitor_producer/src/eventmon_config.cpp b/producer/event_monitor_producer/src/eventmon_config.cpp
index 37a1cb467..5341fd14c 100644
--- a/producer/event_monitor_producer/src/eventmon_config.cpp
+++ b/producer/event_monitor_producer/src/eventmon_config.cpp
@@ -28,7 +28,7 @@ Error DatasetModeToEnum(const std::string& mode_str, DatasetMode* mode) {
     }
 
 
-    return TextError("Wrone dataset mode:" + mode_str);
+    return GeneralErrorTemplates::kSimpleError.Generate("Wrone dataset mode:" + mode_str);
 }
 
 Error EventMonConfigFactory::ParseConfigFile(std::string file_name) {
@@ -95,7 +95,7 @@ Error EventMonConfigFactory::CheckMode() {
     } else if (config.mode_str == "filesystem") {
         config.mode = RequestHandlerType::kFilesystem;
     } else {
-        return  TextError("wrong producer mode: " + config.mode_str);
+        return  GeneralErrorTemplates::kSimpleError.Generate("wrong producer mode: " + config.mode_str);
     }
     return nullptr;
 }
@@ -108,19 +108,20 @@ Error EventMonConfigFactory::CheckLogLevel() {
 
 Error EventMonConfigFactory::CheckNThreads() {
     if (config.nthreads == 0 || config.nthreads > kMaxProcessingThreads ) {
-        return  TextError("NThreads should between 1 and " + std::to_string(kMaxProcessingThreads));
+        return  GeneralErrorTemplates::kSimpleError.Generate("NThreads should between 1 and " + std::to_string(
+                    kMaxProcessingThreads));
     }
     return nullptr;
 }
 
 Error EventMonConfigFactory::CheckDatasets() {
     if (config.dataset_mode == DatasetMode::kBatch && config.dataset_batch_size < 1) {
-        return  TextError("Batch size should > 0");
+        return  GeneralErrorTemplates::kSimpleError.Generate("Batch size should > 0");
     }
 
 
     if (config.dataset_mode == DatasetMode::kMultiSource && config.dataset_multisource_nsources < 1) {
-        return  TextError("Number of sources size should be > 0");
+        return  GeneralErrorTemplates::kSimpleError.Generate("Number of sources size should be > 0");
     }
 
 
diff --git a/producer/event_monitor_producer/src/folder_event_detector.cpp b/producer/event_monitor_producer/src/folder_event_detector.cpp
index e108144ba..3cabedc5f 100644
--- a/producer/event_monitor_producer/src/folder_event_detector.cpp
+++ b/producer/event_monitor_producer/src/folder_event_detector.cpp
@@ -59,7 +59,7 @@ Error FolderEventDetector::UpdateEventsBuffer() {
 
 Error FolderEventDetector::GetNextEvent(MessageHeader* message_header) {
     if (!monitoring_started_) {
-        auto err = TextError("monitoring is not started yet");
+        auto err = GeneralErrorTemplates::kSimpleError.Generate("monitoring is not started yet");
         return err;
     }
 
diff --git a/producer/event_monitor_producer/unittests/test_folder_event_detector.cpp b/producer/event_monitor_producer/unittests/test_folder_event_detector.cpp
index c1c8b43a0..66d543326 100644
--- a/producer/event_monitor_producer/unittests/test_folder_event_detector.cpp
+++ b/producer/event_monitor_producer/unittests/test_folder_event_detector.cpp
@@ -101,7 +101,7 @@ TEST_F(FolderEventDetectorTests, StartFolderMonitoringReturnsError) {
     EXPECT_CALL(mock_system_folder_watch, StartFolderMonitor_t(expected_root_folder, expected_folders))
     .Times(2)
     .WillOnce(
-        Return(asapo::ErrorTemplates::kMemoryAllocationError.Generate().release())
+        Return(asapo::GeneralErrorTemplates::kMemoryAllocationError.Generate().release())
     )
     .WillOnce(
         Return(nullptr)
diff --git a/receiver/src/receiver_data_server/net_server/rds_fabric_server.cpp b/receiver/src/receiver_data_server/net_server/rds_fabric_server.cpp
index 3c07fd785..a31ab1874 100644
--- a/receiver/src/receiver_data_server/net_server/rds_fabric_server.cpp
+++ b/receiver/src/receiver_data_server/net_server/rds_fabric_server.cpp
@@ -19,7 +19,7 @@ RdsFabricServer::~RdsFabricServer() {
 
 Error RdsFabricServer::Initialize() {
     if (server__) {
-        return TextError("Server was already initialized");
+        return GeneralErrorTemplates::kSimpleError.Generate("Server was already initialized");
     }
     Error err;
     std::string hostname;
diff --git a/receiver/src/receiver_data_server/net_server/rds_tcp_server.cpp b/receiver/src/receiver_data_server/net_server/rds_tcp_server.cpp
index eacb5fc0d..fc8efd3fe 100644
--- a/receiver/src/receiver_data_server/net_server/rds_tcp_server.cpp
+++ b/receiver/src/receiver_data_server/net_server/rds_tcp_server.cpp
@@ -19,7 +19,7 @@ Error RdsTcpServer::Initialize() {
             log__->Error("TCP ReceiverDataServer cannot listen on " + address_ + ": " + err->Explain());
         }
     } else {
-        err = TextError("Server was already initialized");
+        err = GeneralErrorTemplates::kSimpleError.Generate("Server was already initialized");
     }
     return err;
 }
@@ -44,7 +44,7 @@ ReceiverDataServerRequestPtr RdsTcpServer::ReadRequest(SocketDescriptor socket,
     GenericRequestHeader header;
     io__->Receive(socket, &header,
                   sizeof(GenericRequestHeader), err);
-    if (*err == ErrorTemplates::kEndOfFile) {
+    if (*err == GeneralErrorTemplates::kEndOfFile) {
         CloseSocket(socket);
         return nullptr;
     } else if (*err) {
diff --git a/receiver/src/receiver_data_server/receiver_data_server_error.h b/receiver/src/receiver_data_server/receiver_data_server_error.h
index 02befb4ca..3e2e48601 100644
--- a/receiver/src/receiver_data_server/receiver_data_server_error.h
+++ b/receiver/src/receiver_data_server/receiver_data_server_error.h
@@ -10,7 +10,7 @@ enum class ReceiverDataServerErrorType {
     kWrongRequest
 };
 
-using ReceiverDataServerErrorTemplate = ServiceErrorTemplate<ReceiverDataServerErrorType, ErrorType::kReceiverError>;
+using ReceiverDataServerErrorTemplate = ServiceErrorTemplate<ReceiverDataServerErrorType>;
 
 namespace ReceiverDataServerErrorTemplates {
 auto const kMemoryPool = ReceiverDataServerErrorTemplate {
diff --git a/receiver/src/receiver_error.h b/receiver/src/receiver_error.h
index 23d0669d6..dbfa6c1e2 100644
--- a/receiver/src/receiver_error.h
+++ b/receiver/src/receiver_error.h
@@ -15,7 +15,7 @@ enum class ReceiverErrorType {
     kUnsupportedClient
 };
 
-using ReceiverErrorTemplate = ServiceErrorTemplate<ReceiverErrorType, ErrorType::kReceiverError>;
+using ReceiverErrorTemplate = ServiceErrorTemplate<ReceiverErrorType>;
 
 
 namespace ReceiverErrorTemplates {
diff --git a/receiver/src/request.cpp b/receiver/src/request.cpp
index 6eb78f82c..b815a33e6 100644
--- a/receiver/src/request.cpp
+++ b/receiver/src/request.cpp
@@ -18,7 +18,7 @@ Error Request::PrepareDataBufferAndLockIfNeeded() {
         try {
             data_buffer_.reset(new uint8_t[(size_t)request_header_.data_size]);
         } catch(std::exception& e) {
-            auto err = ErrorTemplates::kMemoryAllocationError.Generate();
+            auto err = GeneralErrorTemplates::kMemoryAllocationError.Generate();
             err->Append(e.what());
             return err;
         }
@@ -28,7 +28,7 @@ Error Request::PrepareDataBufferAndLockIfNeeded() {
         if (data_ptr) {
             slot_meta_ = slot;
         } else {
-            return ErrorTemplates::kMemoryAllocationError.Generate("cannot allocate slot in cache");
+            return GeneralErrorTemplates::kMemoryAllocationError.Generate("cannot allocate slot in cache");
         }
     }
     return nullptr;
diff --git a/receiver/src/request_handler/request_handler_db.cpp b/receiver/src/request_handler/request_handler_db.cpp
index 60ad1eb96..38d6ef6c2 100644
--- a/receiver/src/request_handler/request_handler_db.cpp
+++ b/receiver/src/request_handler/request_handler_db.cpp
@@ -39,10 +39,9 @@ Error RequestHandlerDb::GetDatabaseServerUri(std::string* uri) const {
     Error http_err;
     *uri = http_client__->Get(GetReceiverConfig()->discovery_server + "/asapo-mongodb", &code, &http_err);
     if (http_err) {
-        log__->Error(
-            std::string{"http error when discover database server "} + " from " + GetReceiverConfig()->discovery_server
-            + " : " + http_err->Explain());
-        return ReceiverErrorTemplates::kInternalServerError.Generate("http error when discover database server" +
+        log__->Error(LogMessageWithFields("http error while discovering database server: " + http_err->Explain()).
+                     Append("origin", GetReceiverConfig()->discovery_server));
+        return ReceiverErrorTemplates::kInternalServerError.Generate("http error while discovering database server: " +
                 http_err->Explain());
     }
 
diff --git a/receiver/src/request_handler/requests_dispatcher.cpp b/receiver/src/request_handler/requests_dispatcher.cpp
index e015ca9eb..827eb713b 100644
--- a/receiver/src/request_handler/requests_dispatcher.cpp
+++ b/receiver/src/request_handler/requests_dispatcher.cpp
@@ -92,7 +92,7 @@ std::unique_ptr<Request> RequestsDispatcher::GetNextRequest(Error* err) const no
     io__->Receive(socket_fd_, &generic_request_header,
                   sizeof(GenericRequestHeader), err);
     if (*err) {
-        if (*err != ErrorTemplates::kEndOfFile) {
+        if (*err != GeneralErrorTemplates::kEndOfFile) {
             log__->Error(LogMessageWithFields("error getting next request: " + (*err)->Explain()).
                          Append("origin", HostFromUri(producer_uri_)));
         }
diff --git a/receiver/unittests/receiver_data_server/net_server/test_rds_tcp_server.cpp b/receiver/unittests/receiver_data_server/net_server/test_rds_tcp_server.cpp
index 83d2d8572..22a0aae33 100644
--- a/receiver/unittests/receiver_data_server/net_server/test_rds_tcp_server.cpp
+++ b/receiver/unittests/receiver_data_server/net_server/test_rds_tcp_server.cpp
@@ -137,7 +137,7 @@ void RdsTCPServerTests::ExpectReceiveRequestEof() {
     for (auto conn : expected_client_sockets) {
         EXPECT_CALL(mock_io, Receive_t(conn, _, _, _))
         .WillOnce(
-            DoAll(SetArgPointee<3>(asapo::ErrorTemplates::kEndOfFile.Generate().release()),
+            DoAll(SetArgPointee<3>(asapo::GeneralErrorTemplates::kEndOfFile.Generate().release()),
                   Return(0))
         );
         EXPECT_CALL(mock_io, CloseSocket_t(conn, _));
diff --git a/receiver/unittests/request_handler/file_processors/test_receive_file_processor.cpp b/receiver/unittests/request_handler/file_processors/test_receive_file_processor.cpp
index cea42b7e8..4a129be53 100644
--- a/receiver/unittests/request_handler/file_processors/test_receive_file_processor.cpp
+++ b/receiver/unittests/request_handler/file_processors/test_receive_file_processor.cpp
@@ -69,7 +69,7 @@ class ReceiveFileProcessorTests : public Test {
                                       asapo::kPathSeparator + expected_year +
                                       asapo::kPathSeparator + "data" +
                                       asapo::kPathSeparator + expected_beamtime_id;
-    void ExpectFileWrite(const asapo::SimpleErrorTemplate* error_template);
+    void ExpectFileWrite(const asapo::ErrorTemplateInterface* error_template);
     void MockRequestData();
     void SetUp() override {
         GenericRequestHeader request_header;
@@ -106,7 +106,7 @@ void ReceiveFileProcessorTests::MockRequestData() {
     .WillRepeatedly(Return(expected_file_name));
 }
 
-void ReceiveFileProcessorTests::ExpectFileWrite(const asapo::SimpleErrorTemplate* error_template) {
+void ReceiveFileProcessorTests::ExpectFileWrite(const asapo::ErrorTemplateInterface* error_template) {
     EXPECT_CALL(mock_io, WriteDataToFile_t(expected_full_path, expected_file_name, _, expected_file_size, true,
                                            expected_overwrite))
     .WillOnce(
diff --git a/receiver/unittests/request_handler/file_processors/test_write_file_processor.cpp b/receiver/unittests/request_handler/file_processors/test_write_file_processor.cpp
index a8be95300..02967f907 100644
--- a/receiver/unittests/request_handler/file_processors/test_write_file_processor.cpp
+++ b/receiver/unittests/request_handler/file_processors/test_write_file_processor.cpp
@@ -68,7 +68,7 @@ class WriteFileProcessorTests : public Test {
                                       asapo::kPathSeparator + expected_year +
                                       asapo::kPathSeparator + "data" +
                                       asapo::kPathSeparator + expected_beamtime_id;
-    void ExpectFileWrite(const asapo::SimpleErrorTemplate* error_template);
+    void ExpectFileWrite(const asapo::ErrorTemplateInterface* error_template);
     void MockRequestData(int times = 1);
     void SetUp() override {
         GenericRequestHeader request_header;
@@ -112,7 +112,7 @@ void WriteFileProcessorTests::MockRequestData(int times) {
     .WillRepeatedly(Return(expected_file_name));
 }
 
-void WriteFileProcessorTests::ExpectFileWrite(const asapo::SimpleErrorTemplate* error_template) {
+void WriteFileProcessorTests::ExpectFileWrite(const asapo::ErrorTemplateInterface* error_template) {
     EXPECT_CALL(mock_io, WriteDataToFile_t(expected_full_path, expected_file_name, _, expected_file_size, true,
                                            expected_overwrite))
     .WillOnce(
diff --git a/receiver/unittests/request_handler/test_authorization_client.cpp b/receiver/unittests/request_handler/test_authorization_client.cpp
index 92028ca47..9a95f2f08 100644
--- a/receiver/unittests/request_handler/test_authorization_client.cpp
+++ b/receiver/unittests/request_handler/test_authorization_client.cpp
@@ -76,7 +76,7 @@ class AuthorizerClientTests : public Test {
             EXPECT_CALL(mock_http_client,
                         Post_t(expected_authorization_server + "/authorize", _, expect_request_string, _, _)).
             WillOnce(
-                DoAll(SetArgPointee<4>(new asapo::SimpleError("http error")),
+                DoAll(SetArgPointee<4>(asapo::GeneralErrorTemplates::kSimpleError.Generate("http error").release()),
                       Return("")
                      ));
         } else {
diff --git a/receiver/unittests/request_handler/test_request_handler_db.cpp b/receiver/unittests/request_handler/test_request_handler_db.cpp
index f17495b88..c9d2b7091 100644
--- a/receiver/unittests/request_handler/test_request_handler_db.cpp
+++ b/receiver/unittests/request_handler/test_request_handler_db.cpp
@@ -64,10 +64,10 @@ void DbHandlerTests::MockAuthRequest(bool error, HttpCode code) {
     if (error) {
         EXPECT_CALL(mock_http_client, Get_t(expected_discovery_server + "/asapo-mongodb",  _, _)).
         WillOnce(
-            DoAll(SetArgPointee<2>(new asapo::SimpleError("http error")),
+            DoAll(SetArgPointee<2>(asapo::GeneralErrorTemplates::kSimpleError.Generate("http error").release()),
                   Return("")
                  ));
-        EXPECT_CALL(mock_logger, Error(AllOf(HasSubstr("discover database server"),
+        EXPECT_CALL(mock_logger, Error(AllOf(HasSubstr("discovering database server"),
                                              HasSubstr("http error"),
                                              HasSubstr(expected_discovery_server))));
 
@@ -171,7 +171,7 @@ TEST_F(DbHandlerTests, ProcessRequestCallsConnectDbWhenNotConnected) {
 TEST_F(DbHandlerTests, ProcessRequestReturnsErrorWhenCannotConnect) {
 
     EXPECT_CALL(mock_db, Connect_t(_, _)).
-    WillOnce(testing::Return(new asapo::SimpleError("")));
+    WillOnce(testing::Return(asapo::GeneralErrorTemplates::kSimpleError.Generate().release()));
 
     auto err = handler.ProcessRequest(mock_request.get());
 
diff --git a/receiver/unittests/request_handler/test_request_handler_file_process.cpp b/receiver/unittests/request_handler/test_request_handler_file_process.cpp
index d8a957ebc..49fc864be 100644
--- a/receiver/unittests/request_handler/test_request_handler_file_process.cpp
+++ b/receiver/unittests/request_handler/test_request_handler_file_process.cpp
@@ -32,7 +32,7 @@ class FileWriteHandlerTests : public Test {
     NiceMock<MockIO> mock_io;
     std::unique_ptr<MockRequest> mock_request;
     NiceMock<asapo::MockLogger> mock_logger;
-    void ExpecFileProcess(const asapo::SimpleErrorTemplate* error_template, bool overwrite);
+    void ExpecFileProcess(const asapo::ErrorTemplateInterface* error_template, bool overwrite);
     void SetUp() override {
         GenericRequestHeader request_header;
         mock_request.reset(new MockRequest{request_header, 1, "", nullptr});
@@ -50,7 +50,7 @@ TEST_F(FileWriteHandlerTests, CheckStatisticEntity) {
     ASSERT_THAT(entity, Eq(asapo::StatisticEntity::kDisk));
 }
 
-void FileWriteHandlerTests::ExpecFileProcess(const asapo::SimpleErrorTemplate* error_template, bool overwrite) {
+void FileWriteHandlerTests::ExpecFileProcess(const asapo::ErrorTemplateInterface* error_template, bool overwrite) {
     EXPECT_CALL(mock_file_processor, ProcessFile_t(mock_request.get(), overwrite))
     .WillOnce(
         Return(error_template == nullptr ? nullptr : error_template->Generate().release()));
diff --git a/receiver/unittests/request_handler/test_request_handler_receive_data.cpp b/receiver/unittests/request_handler/test_request_handler_receive_data.cpp
index 71e8f1cb2..33039cf30 100644
--- a/receiver/unittests/request_handler/test_request_handler_receive_data.cpp
+++ b/receiver/unittests/request_handler/test_request_handler_receive_data.cpp
@@ -148,7 +148,7 @@ TEST_F(ReceiveDataHandlerTests, ErrorGetMemoryFromCache) {
     auto err = handler.ProcessRequest(request.get());
 
     ASSERT_THAT(request->GetSlotId(), Eq(0));
-    ASSERT_THAT(err, Eq(asapo::ErrorTemplates::kMemoryAllocationError));
+    ASSERT_THAT(err, Eq(asapo::GeneralErrorTemplates::kMemoryAllocationError));
 }
 
 
diff --git a/receiver/unittests/request_handler/test_requests_dispatcher.cpp b/receiver/unittests/request_handler/test_requests_dispatcher.cpp
index 05e96a8a8..e0303fded 100644
--- a/receiver/unittests/request_handler/test_requests_dispatcher.cpp
+++ b/receiver/unittests/request_handler/test_requests_dispatcher.cpp
@@ -158,13 +158,13 @@ TEST_F(RequestsDispatcherTests, ClosedConnectionOnReceivetNextRequest) {
     EXPECT_CALL(mock_statictics, StartTimer_t(StatisticEntity::kNetwork));
     EXPECT_CALL(mock_io, Receive_t(_, _, _, _))
     .WillOnce(
-        DoAll(SetArgPointee<3>(asapo::ErrorTemplates::kEndOfFile.Generate().release()),
+        DoAll(SetArgPointee<3>(asapo::GeneralErrorTemplates::kEndOfFile.Generate().release()),
               Return(0))
     );
     Error err;
     dispatcher->GetNextRequest(&err);
 
-    ASSERT_THAT(err, Eq(asapo::ErrorTemplates::kEndOfFile));
+    ASSERT_THAT(err, Eq(asapo::GeneralErrorTemplates::kEndOfFile));
 }
 
 
diff --git a/receiver/unittests/test_connection.cpp b/receiver/unittests/test_connection.cpp
index ee49f8c51..d8d24445a 100644
--- a/receiver/unittests/test_connection.cpp
+++ b/receiver/unittests/test_connection.cpp
@@ -2,6 +2,7 @@
 #include <gmock/gmock.h>
 
 #include "asapo/unittests/MockIO.h"
+#include "asapo/common/error.h"
 #include "asapo/unittests/MockLogger.h"
 #include "../src/connection.h"
 #include "receiver_mocking.h"
@@ -71,7 +72,7 @@ class ConnectionTests : public Test {
         if (error ) {
             EXPECT_CALL(mock_dispatcher, GetNextRequest_t(_))
             .WillOnce(DoAll(
-                          SetArgPointee<0>(new asapo::SimpleError{"error"}),
+                          SetArgPointee<0>(asapo::GeneralErrorTemplates::kSimpleError.Generate("error").release()),
                           Return(nullptr)
                       ));
             return nullptr;
@@ -91,7 +92,7 @@ class ConnectionTests : public Test {
         if (error ) {
             EXPECT_CALL(mock_dispatcher, ProcessRequest_t(request))
             .WillOnce(
-                Return(new asapo::SimpleError{"error"})
+                Return(asapo::GeneralErrorTemplates::kSimpleError.Generate("error").release())
             );
         } else {
             EXPECT_CALL(mock_dispatcher, ProcessRequest_t(request))
diff --git a/tests/automatic/system_io/ip_tcp_network/client_serv/ip_tcp_network.cpp b/tests/automatic/system_io/ip_tcp_network/client_serv/ip_tcp_network.cpp
index 2e15db04e..bbc90c53f 100644
--- a/tests/automatic/system_io/ip_tcp_network/client_serv/ip_tcp_network.cpp
+++ b/tests/automatic/system_io/ip_tcp_network/client_serv/ip_tcp_network.cpp
@@ -8,7 +8,6 @@
 #include "testing.h"
 
 using asapo::Error;
-using asapo::ErrorType;
 using asapo::AddressFamilies;
 using asapo::SocketTypes;
 using asapo::SocketProtocols;
@@ -62,7 +61,7 @@ std::unique_ptr<std::thread> CreateEchoServerThread() {
                     if (asapo::IOErrorTemplates::kTimeout == err) {
                         continue;
                     }
-                    if (asapo::ErrorTemplates::kEndOfFile == err) {
+                    if (asapo::GeneralErrorTemplates::kEndOfFile == err) {
                         break;
                     }
                 }
diff --git a/tests/automatic/system_io/ip_tcp_network/client_serv_multicon/multicon.cpp b/tests/automatic/system_io/ip_tcp_network/client_serv_multicon/multicon.cpp
index 2022b66f4..faaecc454 100644
--- a/tests/automatic/system_io/ip_tcp_network/client_serv_multicon/multicon.cpp
+++ b/tests/automatic/system_io/ip_tcp_network/client_serv_multicon/multicon.cpp
@@ -8,7 +8,6 @@
 #include "testing.h"
 
 using asapo::Error;
-using asapo::ErrorType;
 using asapo::AddressFamilies;
 using asapo::SocketTypes;
 using asapo::SocketProtocols;
@@ -51,7 +50,7 @@ std::unique_ptr<std::thread> CreateEchoServerThread() {
                 std::cout << "[SERVER] processing socket " << socket << std::endl;
                 uint64_t message;
                 io->Receive(socket, &message, sizeof(uint64_t), &err);
-                if (err == asapo::ErrorTemplates::kEndOfFile) {
+                if (err == asapo::GeneralErrorTemplates::kEndOfFile) {
                     std::cout << "[SERVER] end of file " << socket << std::endl;
                     io->CloseSocket(socket, &err);
                     ExitIfErrIsNotOk(&err, 106);
diff --git a/tests/automatic/system_io/resolve_hostname_to_ip/resolve_hostname_to_ip.cpp b/tests/automatic/system_io/resolve_hostname_to_ip/resolve_hostname_to_ip.cpp
index da90ded0b..79a09683b 100644
--- a/tests/automatic/system_io/resolve_hostname_to_ip/resolve_hostname_to_ip.cpp
+++ b/tests/automatic/system_io/resolve_hostname_to_ip/resolve_hostname_to_ip.cpp
@@ -4,7 +4,6 @@
 #include "testing.h"
 
 using asapo::Error;
-using asapo::ErrorType;
 
 void Check(const std::string& expected_ip_address, const std::string& hostname) {
     std::cout << "Checking: " << hostname << std::endl;
-- 
GitLab