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

Constructor

exception(kc::code rcode)

explicit exception(kc::code rcode)

Creates an exception with the specified error code.

Parameters:

  • rcode - The error code indicating the specific failure condition

Methods

code()

kc::code code() const noexcept

Returns the error code associated with this exception.

Returns: The kc::code (std::error_code) representing the specific error condition

what()

const char* what() const noexcept override

Returns a generic description of the exception type.

Returns: "keychain exception"

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

temporal_exception

class temporal_exception : public kc::exception

Thrown when time-related constraints are violated.

Common Scenarios: * Certificate expiration or not-yet-valid conditions * Timestamp validation failures in verifiable data * Consensus timeout conditions

internal_exception

class internal_exception : public kc::exception

Thrown when internal library state becomes inconsistent or unexpected conditions occur.

Common Scenarios: * Database corruption or inconsistency * Cryptographic library internal errors * Resource allocation failures

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");
}
  • 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