Enum Class SdkErrorCode

java.lang.Object
java.lang.Enum<SdkErrorCode>
co.ankatech.ankasecure.sdk.exception.SdkErrorCode
All Implemented Interfaces:
Serializable, Comparable<SdkErrorCode>, Constable

public enum SdkErrorCode extends Enum<SdkErrorCode>
High-level, protocol-agnostic error categories recognised by the SDK.

These error codes provide a consistent way to classify failures across all SDK operations, allowing consumers to implement appropriate error handling and retry strategies.

Error Handling Strategy by Code


 try {
     result = sdk.encrypt("my-key", data);
 } catch (AnkaSecureSdkException e) {
     switch (e.getErrorCode()) {
         case TIMEOUT:
             // Retry with exponential backoff
             retryWithBackoff(operation);
             break;
         case IO:
             // Check network connectivity, verify TLS certificates
             validateNetworkAndRetry();
             break;
         case HTTP:
             // Inspect HTTP status code for specific error
             handleHttpError(e.getHttpStatus(), e.getResponseBody());
             break;
         case UNKNOWN:
             // Log full context and alert operations team
             logger.error("Unknown error: {}", e.getMessage(), e);
             alertOps(e);
             break;
     }
 }
 
Since:
2.2.0
Author:
ANKATech – Security Engineering
  • Enum Constant Details

    • TIMEOUT

      public static final SdkErrorCode TIMEOUT
      Network stack detected a connect, read, or write timeout.

      Common causes:

      • API server is overloaded or unresponsive
      • Network latency exceeds configured timeout
      • Large file operations exceeding default timeout
      • Firewall or proxy blocking connection

      Recovery: Implement exponential backoff retry. Increase timeout in cli.properties (api.timeoutMs) if consistently timing out on legitimate operations.

      Example:

      
       // Retry with backoff
       int retries = 3;
       int delayMs = 1000;
       for (int i = 0; i < retries; i++) {
           try {
               return sdk.encrypt("key", data);
           } catch (AnkaSecureSdkException e) {
               if (e.getErrorCode() == SdkErrorCode.TIMEOUT && i < retries - 1) {
                   Thread.sleep(delayMs);
                   delayMs *= 2; // exponential backoff
               } else {
                   throw e;
               }
           }
       }
       
    • IO

      public static final SdkErrorCode IO
      Generic I/O problem during HTTP communication.

      Common causes:

      • Host unreachable (network down, incorrect API URL)
      • TLS/SSL handshake failure (invalid certificate, protocol mismatch)
      • DNS resolution failure
      • Connection reset by peer
      • Proxy configuration error

      Recovery: Verify network connectivity, check api.baseUrl in cli.properties, validate TLS certificates, check proxy settings.

      Diagnostics: Check Throwable.getCause() for underlying IOException or SSLException details.

      Example:

      
       try {
           sdk.authenticateApplication(clientId, secret);
       } catch (AnkaSecureSdkException e) {
           if (e.getErrorCode() == SdkErrorCode.IO) {
               Throwable cause = e.getCause();
               if (cause instanceof SSLException) {
                   logger.error("TLS error: {}. Check server certificate.", cause.getMessage());
               } else if (cause instanceof UnknownHostException) {
                   logger.error("Cannot resolve host. Check api.baseUrl: {}", apiBaseUrl);
               }
           }
       }
       
    • HTTP

      public static final SdkErrorCode HTTP
      Remote endpoint replied with an HTTP 4xx (client error) or 5xx (server error).

      Common HTTP status codes:

      • 400 Bad Request: Invalid input, malformed request, or key does not support operation
      • 401 Unauthorized: Invalid or expired authentication token
      • 403 Forbidden: Insufficient permissions or quota exceeded
      • 404 Not Found: Requested resource (e.g., key) does not exist
      • 409 Conflict: Resource already exists (e.g., duplicate key ID)
      • 429 Too Many Requests: Rate limit exceeded
      • 500 Internal Server Error: Server-side failure
      • 503 Service Unavailable: Server temporarily down or overloaded

      Recovery: Inspect AnkaSecureSdkException.getHttpStatus() and AnkaSecureSdkException.getResponseBody() for specific error details. Implement retry for 5xx errors, re-authenticate for 401, adjust request for 4xx errors.

      Example:

      
       try {
           sdk.encrypt(kid, data);
       } catch (AnkaSecureSdkException e) {
           if (e.getErrorCode() == SdkErrorCode.HTTP) {
               int status = e.getHttpStatus();
               String body = e.getResponseBody();
      
               if (status == 401) {
                   logger.warn("Token expired, re-authenticating...");
                   sdk.authenticateApplication(clientId, secret);
                   return sdk.encrypt(kid, data); // retry
               } else if (status == 404) {
                   logger.info("Key not found: {}", kid);
                   return sdk.getKeyMetadata(kid);
               } else if (status >= 500) {
                   logger.error("Server error {}: {}", status, body);
                   // implement retry with backoff
               } else {
                   logger.error("Client error {}: {}", status, body);
               }
           }
       }
       
    • UNKNOWN

      public static final SdkErrorCode UNKNOWN
      Failure that cannot be classified into TIMEOUT, IO, or HTTP.

      Common causes:

      • Unexpected exception in SDK internal logic
      • Malformed response from server (JSON parsing failure)
      • SDK bug or unsupported edge case
      • Runtime environment issue (missing classes, permissions)

      Recovery: This is typically non-recoverable. Log full exception details including AnkaSecureSdkException.getContext(), Throwable.getCause(), and AnkaSecureSdkException.getResponseBody() for diagnostics. Report to AnkaTech support if consistently occurring.

      Example:

      
       try {
           result = sdk.decrypt(jwe);
       } catch (AnkaSecureSdkException e) {
           if (e.getErrorCode() == SdkErrorCode.UNKNOWN) {
               logger.error("Unknown SDK error. Please report to support.");
               logger.error("Message: {}", e.getMessage());
               logger.error("Context: {}", e.getContext());
               logger.error("Response body: {}", e.getResponseBody());
               logger.error("Cause: ", e.getCause());
      
               // Alert operations team
               alertOps("Unknown SDK error", e);
           }
       }
       
    • REENCRYPT_DEGENERATE_SAME_KID

      public static final SdkErrorCode REENCRYPT_DEGENERATE_SAME_KID
      Degenerate same-kid rotation rejected by the SDK's ReencryptInvariantGuard (defense-in-depth on top of the server-side REENCRYPT-as-first-class invariant).

      Raised when a REENCRYPT or RESIGN response from core-api carries newKeyRequested.equals(oldKeyRequested) — that is, the rotation collapsed to a no-op kid mapping. Per workspace policy (workspace memory user_reencryption_is_core_patent.md), cross-kid rotation is core IP; same-kid is degenerate and must never succeed silently.

      The exception message distinguishes REENCRYPT vs RESIGN via the literal in the message body; a single error code is shared between both rotation primitives (architect D-A5).

      Recovery: none — surface to the operator and fix the rotation request to use distinct kids.

      Since:
      this feature (jose-wire-consumer-alignment).
    • MULTIRECIPIENT_NOT_COMPACT_REPRESENTABLE

      public static final SdkErrorCode MULTIRECIPIENT_NOT_COMPACT_REPRESENTABLE
      Multi-recipient JWE / multi-signature JWS rejected by the SDK's Compact-format public API surface (architect D-A2).

      COMPOSITE hybrid keys produce JWE General JSON with multiple recipients (e.g. ML-KEM-768 + RSA-OAEP-3072) or JWS General JSON with multiple signatures (e.g. ML-DSA-65 + RSA-PSS-3072). Compact Serialization (RFC 7516 §7.1 / RFC 7515 §7.1) cannot natively represent either case — Compact is five segments (JWE) or three segments (JWS), with exactly one recipient / signature.

      The SDK exposes Compact strings on its public contract (EncryptResult.jweToken : String etc.). When a caller invokes a *Compact method with a kid that resolves to a COMPOSITE hybrid key, the response carries multiple recipients/signatures and the SDK throws this code rather than silently swap the file format to General JSON.

      Recovery: use the typed General JSON API (out of scope for this feature; planned as a follow-up). The kid in the caller's request is COMPOSITE — to operate on it via Compact, the caller must split into per-recipient SIMPLE keys, which is not the intended usage.

      Since:
      this feature (jose-wire-consumer-alignment).
  • Method Details

    • values

      public static SdkErrorCode[] values()
      Returns an array containing the constants of this enum class, in the order they are declared.
      Returns:
      an array containing the constants of this enum class, in the order they are declared
    • valueOf

      public static SdkErrorCode valueOf(String name)
      Returns the enum constant of this class with the specified name. The string must match exactly an identifier used to declare an enum constant in this class. (Extraneous whitespace characters are not permitted.)
      Parameters:
      name - the name of the enum constant to be returned.
      Returns:
      the enum constant with the specified name
      Throws:
      IllegalArgumentException - if this enum class has no constant with the specified name
      NullPointerException - if the argument is null