Enum Class SdkErrorCode
- All Implemented Interfaces:
Serializable,Comparable<SdkErrorCode>,Constable
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 STATEFUL_KEY_BUSY:
// Transient: retry after e.getRetryAfterSeconds()
retryAfter(e.getRetryAfterSeconds(), operation);
break;
case STATEFUL_KEY_EXHAUSTED:
// Permanent for this key: rotate it, do not retry
scheduleRotation(kid);
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;
}
}
-
Nested Class Summary
Nested classes/interfaces inherited from class java.lang.Enum
Enum.EnumDesc<E extends Enum<E>> -
Enum Constant Summary
Enum ConstantsEnum ConstantDescriptionRemote endpoint replied with an HTTP 4xx (client error) or 5xx (server error).Generic I/O problem during HTTP communication.A JWE or JWS supplied by the caller is not a well-formed JOSE serialization the SDK can send, and was refused on the client before any request was made.Degenerate same-kid rotation rejected by the SDK'sReencryptInvariantGuard(defense-in-depth on top of the server-side REENCRYPT-as-first-class invariant).Another request is reserving the next one-time signature of the same stateful hash-based key (XMSS, XMSS^MT, LMS/HSS).A stateful hash-based signature key (XMSS, XMSS^MT, LMS/HSS) cannot produce another signature.Network stack detected a connect, read, or write timeout. -
Method Summary
Modifier and TypeMethodDescriptionstatic SdkErrorCodeReturns the enum constant of this class with the specified name.static SdkErrorCode[]values()Returns an array containing the constants of this enum class, in the order they are declared.Methods inherited from class java.lang.Enum
compareTo, describeConstable, equals, getDeclaringClass, hashCode, name, ordinal, toString, valueOf
-
Enum Constant Details
-
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(openapi.readTimeoutMs) 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
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
Not a local file. A file the caller named that cannot be read or written is never
IO: it is reported asLocalFileException, whose recovery is local.Recovery: Verify network connectivity, check
openapi.hostincli.properties, validate TLS certificates, check proxy settings.Diagnostics: Check
Throwable.getCause()for underlyingIOExceptionorSSLExceptiondetails.Example:
try { sdk = factory.authenticateApplication(clientId, clientSecret); } 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 openapi.host: {}", apiHost); } } } -
HTTP
Remote endpoint replied with an HTTP 4xx (client error) or 5xx (server error).A refusal the SDK recognises by its RFC 9457 problem
typecarries its own code instead:STATEFUL_KEY_EXHAUSTEDandSTATEFUL_KEY_BUSY.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), or the key is in a state that refuses the operation
- 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()andAnkaSecureSdkException.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 = factory.authenticateApplication(clientId, clientSecret); 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
Failure that cannot be classified intoTIMEOUT,IO, orHTTP.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)
Check the exception's type first. A failure the caller can act on locally is reported as
UNKNOWNand identified by its type, not by this code:LocalFileException(an input that cannot be read, a result that cannot be written),DestinationExistsException,StaleSidecarException. A failure of the HTTP exchange is neverUNKNOWN; it isIOorTIMEOUT.Recovery: Otherwise this is typically non-recoverable. Log full exception details including
AnkaSecureSdkException.getContext(),Throwable.getCause(), andAnkaSecureSdkException.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
Degenerate same-kid rotation rejected by the SDK'sReencryptInvariantGuard(defense-in-depth on top of the server-side REENCRYPT-as-first-class invariant).Raised when a REENCRYPT or RESIGN response from the server carries
newKeyRequested.equals(oldKeyRequested)— that is, the rotation collapsed to a no-op kid mapping. Cross-kid rotation is the purpose of these operations; 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.
Recovery: none — surface to the operator and fix the rotation request to use distinct kids.
-
MALFORMED_JOSE_INPUT
A JWE or JWS supplied by the caller is not a well-formed JOSE serialization the SDK can send, and was refused on the client before any request was made.Every operation that takes a JWE or JWS string or file (decrypt, re-encrypt, decrypt-then-verify, verify, re-sign) reads it as the Compact Serialization (RFC 7516 §7.1 / RFC 7515 §7.1) or the General JSON Serialization (§7.2), chosen by the content. The input is refused with this code when:
- it is neither a JSON object nor the right number of dot-separated segments;
- a Compact segment or a General JSON member is not base64url (RFC 7515 §2: the URL-safe alphabet, no padding), or the protected header does not decode to a JSON object;
- a JSON input does not parse, repeats a member name, lacks the
recipients/signaturesarray or a member the wire requires (a JWS entry'ssignature; a JWE recipient'sencrypted_keyis required only to be base64url when present — RFC 7516 §7.2.1 makes it absent for an empty key, as withalg=dir), or uses a form the wire does not carry: the flattened serialization (§7.2.2), a JWEaadorunprotectedmember; - a JWS declares an unencoded payload (
"b64": false, RFC 7797) or has an empty signature (an unsecured JWS, RFC 7518 §3.6).
The message names the serialization and the defect and never echoes the input; the exception carries no cause.
AnkaSecureSdkException.getHttpStatus()is0.Recovery: not retryable. Supply the artifact exactly as the SDK or the server produced it; convert a flattened serialization to the General one.
A malformed JOSE artifact in a server response is not this code: it is a server contract violation, reported as
UNKNOWN. -
STATEFUL_KEY_EXHAUSTED
A stateful hash-based signature key (XMSS, XMSS^MT, LMS/HSS) cannot produce another signature. Permanent for that key.Raised for an HTTP 409 whose problem
typeishttps://docs.ankatech.co/errors/stateful-key-exhausted. Two causes share it: every one-time signature the key holds has been used, or the key existed in a database that was later restored, so the server can no longer prove an index has not been spent before. The refusal is decided before any output exists; a streaming operation writes no result.Every operation that produces a signature can raise it:
sign,signFileCompact,signFileStream,signThenEncrypt*,resign*(the new key is the one that signs) andconvertPkcs7ToJose*.Recovery: not retryable — the same request with the same key is refused again. Rotate the key (or sign with another one). The signatures the key already produced still verify.
catch (AnkaSecureSdkException e) { if (e.getErrorCode() == SdkErrorCode.STATEFUL_KEY_EXHAUSTED) { logger.warn("Key {} has no one-time signature left; rotate it", kid); } } } -
STATEFUL_KEY_BUSY
Another request is reserving the next one-time signature of the same stateful hash-based key (XMSS, XMSS^MT, LMS/HSS). Transient.Raised for an HTTP 409 whose problem
typeishttps://docs.ankatech.co/errors/stateful-key-busy. The server sends aRetry-Afterheader (whole seconds, at least1), exposed asAnkaSecureSdkException.getRetryAfterSeconds(). The key use the server already admitted is kept, and the refusal is decided before any output exists. Raised by the same operations asSTATEFUL_KEY_EXHAUSTED.Recovery: retry the same request after
AnkaSecureSdkException.getRetryAfterSeconds()seconds. Anullvalue means the header was absent or not in integer-seconds form; wait at least one second.catch (AnkaSecureSdkException e) { if (e.getErrorCode() == SdkErrorCode.STATEFUL_KEY_BUSY) { Long seconds = e.getRetryAfterSeconds(); Thread.sleep(1000L * (seconds == null ? 1L : seconds)); return sdk.sign(kid, data); } } }
-
-
Method Details
-
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
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 nameNullPointerException- if the argument is null
-