exception Class
#include <keychain/exceptions.hpp>
Namespace: keychain
(alias: kc
)
Inheritance: public std::exception
Overview
The exception
class is the base exception class for all {keychain-core} exceptions. It provides structured error handling with integration to the standard library’s std::error_code
system, allowing applications to handle both exceptional conditions and programmatic error checking.
All keychain exceptions inherit from std::exception
and preserve the original error code that caused the exceptional condition, enabling both traditional exception handling and modern error code-based error handling patterns.
Since: v2.0
Methods
Derived Exception Classes
invalid_input
class invalid_input : public kc::exception
Thrown when input parameters are invalid, malformed, or out of acceptable ranges.
Common Scenarios: * Invalid serialization format specifications * Malformed cryptographic parameters * Invalid persona or contact identifiers * Unsupported algorithm selections
invalid_length
class invalid_length : public kc::exception
Thrown when data length constraints are violated.
Common Scenarios: * Cryptographic key sizes that don’t match algorithm requirements * Data payloads that exceed maximum allowed sizes * Insufficient data for deserialization operations
Error Codes
The keychain exception system uses kc::code
(std::error_code) to provide specific error information:
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,
// ... and many more
};
}
Usage Examples
Basic Exception Handling
#include <keychain/keychain_headers.hpp>
try {
kc::persona persona = gateway.create_persona(
"test", "user", kc::security_level::medium
);
// Perform operations...
} catch (const kc::invalid_input& e) {
std::cerr << "Invalid input: " << e.what() << std::endl;
std::cerr << "Error code: " << e.code() << std::endl;
std::cerr << "Error message: " << e.code().message() << std::endl;
} catch (const kc::temporal_exception& e) {
std::cerr << "Temporal error: " << e.code().message() << std::endl;
} catch (const kc::exception& e) {
std::cerr << "Keychain error: " << e.what() << std::endl;
std::cerr << "Error code: " << e.code() << std::endl;
} catch (const std::exception& e) {
std::cerr << "General error: " << e.what() << std::endl;
}
Error Code Analysis
void handle_keychain_error(const kc::exception& e) {
kc::code error_code = e.code();
// Check specific error conditions
if (error_code == kc::error::persona_not_found) {
std::cout << "Persona doesn't exist - creating new one" << std::endl;
// Handle missing persona
} else if (error_code == kc::error::verification) {
std::cout << "Signature verification failed" << std::endl;
// Handle verification failure
} else if (error_code == kc::error::encryption ||
error_code == kc::error::decryption) {
std::cout << "Cryptographic operation failed" << std::endl;
// Handle crypto errors
} else {
std::cout << "Other error: " << error_code.message() << std::endl;
}
// Check error categories
if (error_code.category() == kc::error::get_error_category()) {
std::cout << "This is a keychain-specific error" << std::endl;
}
}
Graceful Degradation
kc::verifiable_data safe_sign_data(
kc::gateway& gateway,
const kc::persona& persona,
const std::string& data
) {
try {
kc::serialized_data serialized_data(data);
return gateway.sign(persona, serialized_data);
} catch (const kc::invalid_input& e) {
if (e.code() == kc::error::persona_not_found) {
throw std::runtime_error("Persona not available for signing");
}
throw; // Re-throw if not a known recoverable error
} catch (const kc::temporal_exception& e) {
if (e.code() == kc::error::certificate_expired) {
throw std::runtime_error("Certificate expired - renewal required");
}
throw;
} catch (const kc::internal_exception& e) {
// Log internal error but don't expose details
std::cerr << "Internal error during signing operation" << std::endl;
throw std::runtime_error("Signing operation failed");
}
}
Exception Translation
// Convert keychain exceptions to application-specific exceptions
class ApplicationError : public std::exception {
std::string message;
public:
ApplicationError(const std::string& msg) : message(msg) {}
const char* what() const noexcept override { return message.c_str(); }
};
void application_operation() {
try {
// Keychain operations...
} catch (const kc::invalid_input& e) {
throw ApplicationError("Invalid user input: " + std::string(e.code().message()));
} catch (const kc::temporal_exception& e) {
throw ApplicationError("Time-related error: " + std::string(e.code().message()));
} catch (const kc::exception& e) {
throw ApplicationError("Cryptographic error: " + std::string(e.code().message()));
}
}
Exception-Safe Resource Management
class SafeGatewayWrapper {
private:
std::unique_ptr<kc::gateway> gateway_ptr;
public:
SafeGatewayWrapper(const kc::settings& settings) {
try {
// Gateway creation through gateway_manager...
} catch (const kc::exception& e) {
std::cerr << "Failed to initialize gateway: " << e.code().message() << std::endl;
throw;
}
}
kc::verifiable_data sign_safely(const kc::persona& persona, const std::string& data) {
if (!gateway_ptr) {
throw std::runtime_error("Gateway not initialized");
}
try {
kc::serialized_data serialized_data(data);
return gateway_ptr->sign(persona, serialized_data);
} catch (const kc::exception& e) {
// Log but don't expose internal details
std::cerr << "Signing failed with error: " << e.code() << std::endl;
throw std::runtime_error("Unable to sign data");
}
}
};
Thread Safety
The exception classes themselves are thread-safe for reading after construction. However, the underlying error code system and gateway operations that may throw exceptions require proper synchronization when used across multiple threads.
Error Recovery Patterns
Retry with Backoff
kc::verifiable_data retry_sign(
kc::gateway& gateway,
const kc::persona& persona,
const kc::serialized_data& data,
int max_retries = 3
) {
for (int attempt = 0; attempt < max_retries; ++attempt) {
try {
return gateway.sign(persona, data);
} catch (const kc::temporal_exception& e) {
if (e.code() == kc::error::consensus_timeout && attempt < max_retries - 1) {
std::this_thread::sleep_for(std::chrono::milliseconds(100 * (1 << attempt)));
continue;
}
throw;
} catch (const kc::internal_exception& e) {
if (attempt < max_retries - 1) {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
continue;
}
throw;
}
}
throw std::runtime_error("Max retry attempts exceeded");
}
Related Classes
-
error - Error code system and categories
-
gateway - Main API that throws keychain exceptions
-
verification_result - Non-exception error reporting for verification
See Also
-
std::error_code - Standard error code system
-
std::exception - Standard exception base class
-
{rfc-7515}[RFC 7515] - JSON Web Signature for error handling patterns