error System
#include <keychain/error.hpp>
Namespace: keychain::error
(alias: kc::error
)
Overview
The error system in {keychain-core} provides comprehensive error handling using the standard library’s std::error_code
system. It defines specific error conditions for all library operations and integrates seamlessly with both exception-based and error code-based error handling patterns.
The system uses strongly-typed error codes that can be compared, categorized, and converted to human-readable messages, enabling robust error handling in cryptographic identity management applications.
Since: v3.0
Error Code Enumeration
error_code_t
namespace kc::error {
enum class error_code_t {
success = 0,
deprecated,
unknown,
file_system,
not_implemented,
persona_exists,
persona_not_found,
contact_exists,
contact_not_found,
payload_too_large,
serialization,
deserialization,
encryption,
decryption,
signature,
verification,
consensus,
certificate_expired,
certificate_not_yet_valid,
invalid_algorithm,
unsupported_format,
database_error,
network_error,
timeout,
access_denied,
resource_exhausted,
// ... and more
};
}
Common Error Codes:
-
success
(0) - Operation completed successfully -
persona_exists
- Attempt to create a persona that already exists -
persona_not_found
- Referenced persona doesn’t exist -
contact_not_found
- Referenced contact doesn’t exist -
serialization
/deserialization
- Data format errors -
encryption
/decryption
- Cryptographic operation failures -
signature
/verification
- Digital signature errors -
consensus
- Consensus protocol errors -
certificate_expired
- PKI certificate validity errors
Console Return Codes
For command-line applications, the error system provides standard exit codes:
namespace kc::error {
constexpr int failure = -1;
constexpr int okay = 0;
constexpr int invalid = 1;
}
Error Categories
The error system uses std::error_category
to group related errors:
const std::error_category& get_error_category() noexcept;
This allows applications to check if an error belongs to the keychain library:
if (error_code.category() == kc::error::get_error_category()) {
// Handle keychain-specific error
}
Usage Examples
Basic Error Checking
#include <keychain/keychain_headers.hpp>
// Function that returns error codes instead of throwing
kc::code create_persona_safe(
kc::gateway& gateway,
const std::string& name,
const std::string& subname,
kc::persona& out_persona
) {
try {
out_persona = gateway.create_persona(name, subname, kc::security_level::medium);
return kc::error::success;
} catch (const kc::exception& e) {
return e.code();
}
}
int main() {
kc::gateway gateway(settings);
kc::persona persona;
kc::code result = create_persona_safe(gateway, "alice", "personal", persona);
if (result == kc::error::success) {
std::cout << "Persona created successfully" << std::endl;
} else if (result == kc::error::persona_exists) {
std::cout << "Persona already exists" << std::endl;
} else {
std::cout << "Error: " << result.message() << std::endl;
return kc::error::failure;
}
return kc::error::okay;
}
Error Code Comparison
void handle_operation_result(kc::code result) {
// Direct comparison with error codes
if (result == kc::error::success) {
std::cout << "Operation successful" << std::endl;
return;
}
// Check for specific error types
if (result == kc::error::persona_not_found ||
result == kc::error::contact_not_found) {
std::cout << "Identity not found - may need to create" << std::endl;
} else if (result == kc::error::certificate_expired) {
std::cout << "Certificate expired - renewal required" << std::endl;
} else if (result == kc::error::encryption ||
result == kc::error::decryption) {
std::cout << "Cryptographic operation failed" << std::endl;
} else if (result == kc::error::verification) {
std::cout << "Signature verification failed" << std::endl;
} else {
std::cout << "Unexpected error: " << result.message() << std::endl;
}
}
Error Code Categories
void analyze_error(kc::code error_code) {
std::cout << "Error: " << error_code.message() << std::endl;
std::cout << "Code: " << error_code.value() << std::endl;
std::cout << "Category: " << error_code.category().name() << std::endl;
// Check if this is a keychain error
if (error_code.category() == kc::error::get_error_category()) {
std::cout << "This is a keychain-specific error" << std::endl;
// Cast to specific error type
auto kc_error = static_cast<kc::error::error_code_t>(error_code.value());
switch (kc_error) {
case kc::error::error_code_t::persona_exists:
std::cout << "Specific handling for persona_exists" << std::endl;
break;
case kc::error::error_code_t::verification:
std::cout << "Specific handling for verification failure" << std::endl;
break;
default:
std::cout << "General keychain error handling" << std::endl;
break;
}
}
}
Creating Error Codes
// Create error codes from enum values
kc::code make_error_code(kc::error::error_code_t e) noexcept {
return kc::code(static_cast<int>(e), kc::error::get_error_category());
}
// Function that returns specific error codes
kc::code validate_persona_name(const std::string& name) {
if (name.empty()) {
return make_error_code(kc::error::error_code_t::invalid_input);
}
if (name.length() > 255) {
return make_error_code(kc::error::error_code_t::payload_too_large);
}
// Check for invalid characters
if (name.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-") != std::string::npos) {
return make_error_code(kc::error::error_code_t::invalid_input);
}
return kc::error::success;
}
Exception and Error Code Integration
// Convert exceptions to error codes
kc::code safe_encrypt(
kc::gateway& gateway,
const kc::persona& persona,
const kc::serialized_data& data,
const std::vector<kc::contact>& recipients,
kc::encrypted_data& out_result
) {
try {
out_result = gateway.encrypt(persona, data, recipients);
return kc::error::success;
} catch (const kc::invalid_input& e) {
return e.code();
} catch (const kc::internal_exception& e) {
return e.code();
} catch (const kc::exception& e) {
return e.code();
} catch (const std::exception&) {
return make_error_code(kc::error::error_code_t::unknown);
}
}
// Convert error codes to exceptions
void throw_on_error(kc::code result) {
if (result == kc::error::success) {
return;
}
auto error_value = static_cast<kc::error::error_code_t>(result.value());
switch (error_value) {
case kc::error::error_code_t::invalid_input:
case kc::error::error_code_t::payload_too_large:
throw kc::invalid_input(result);
case kc::error::error_code_t::certificate_expired:
case kc::error::error_code_t::timeout:
throw kc::temporal_exception(result);
case kc::error::error_code_t::database_error:
case kc::error::error_code_t::resource_exhausted:
throw kc::internal_exception(result);
default:
throw kc::exception(result);
}
}
Error Logging and Monitoring
#include <sstream>
#include <chrono>
class ErrorLogger {
public:
static void log_error(kc::code error_code, const std::string& context = "") {
auto now = std::chrono::system_clock::now();
auto time_t = std::chrono::system_clock::to_time_t(now);
std::ostringstream log_entry;
log_entry << "[" << std::put_time(std::localtime(&time_t), "%Y-%m-%d %H:%M:%S") << "] ";
log_entry << "ERROR: " << error_code.message();
log_entry << " (code: " << error_code.value() << ")";
if (!context.empty()) {
log_entry << " Context: " << context;
}
// Log to file, syslog, or monitoring system
std::cerr << log_entry.str() << std::endl;
// Send to monitoring system for specific error types
if (error_code == kc::error::verification ||
error_code == kc::error::certificate_expired) {
send_to_monitoring_system(error_code, context);
}
}
private:
static void send_to_monitoring_system(kc::code error_code, const std::string& context) {
// Implementation for monitoring system integration
}
};
// Usage in application code
kc::code result = gateway_operation();
if (result != kc::error::success) {
ErrorLogger::log_error(result, "Gateway persona creation");
handle_operation_result(result);
}
Custom Error Conditions
// Application-specific error handling
bool is_recoverable_error(kc::code error_code) {
return error_code == kc::error::timeout ||
error_code == kc::error::network_error ||
error_code == kc::error::resource_exhausted;
}
bool is_user_error(kc::code error_code) {
return error_code == kc::error::invalid_input ||
error_code == kc::error::persona_not_found ||
error_code == kc::error::contact_not_found;
}
bool is_security_error(kc::code error_code) {
return error_code == kc::error::verification ||
error_code == kc::error::signature ||
error_code == kc::error::access_denied ||
error_code == kc::error::certificate_expired;
}
void handle_error_by_category(kc::code error_code) {
if (is_user_error(error_code)) {
std::cout << "User action required: " << error_code.message() << std::endl;
} else if (is_security_error(error_code)) {
std::cout << "Security error: " << error_code.message() << std::endl;
// Additional security logging
} else if (is_recoverable_error(error_code)) {
std::cout << "Temporary error: " << error_code.message() << std::endl;
// Retry logic
} else {
std::cout << "System error: " << error_code.message() << std::endl;
// System-level error handling
}
}
Best Practices
Error Code Checking
-
Always check return values for functions that return
kc::code
-
Use specific error code comparisons rather than just checking for success/failure
-
Provide meaningful error messages to users based on specific error codes
Integration with TKCrypt
The keychain error system integrates with the underlying TKCrypt library error system (tkc::error
). TKCrypt errors are typically converted to keychain errors at the API boundary, providing a unified error interface for applications.
See Also
-
exception - Exception classes that use this error system
-
gateway - Main API that uses error codes and exceptions
-
std::error_code - Standard error code documentation
-
std::error_category - Error categorization system