Stateful Key Exhausted
URI: https://docs.ankatech.co/errors/stateful-key-exhausted
HTTP Status: 409 Conflict
When you see this
A signing request named a stateful hash-based signature key — XMSS, XMSS^MT, LMS or HSS — that cannot produce another signature. Every signature such a key produces uses a one-time index, and an index must never be used twice: two signatures under one index are enough to forge. The platform commits each index as spent before the signature exists, so a key whose indices are used up, or whose state can no longer be trusted, is refused here. Nothing was signed and nothing was written.
The key itself is not changed by the refusal: it keeps its status, and every signature it already produced still verifies.
Common Causes
- Every one-time signature has been used. The key has reached its capacity: 1,024 signatures for
XMSS-SHA2_10_256, 1,048,576 forXMSSMT-SHA2_20/2_256, 1,023 for each ofLMS-SHA256-M32-H10-W4andLMS-SHA256-M24-H10-W4and 1,048,575 forLMS-HSS-L2-SHA256-M32-H10-W4. An LMS or HSS key keeps its last index unspent, so its capacity is one less than its tree size. - The key existed in a database that was later restored from a backup. A restored copy holds the index the key had when the backup was taken, and that index may have been spent afterwards. Every stateful key material created at or before the restore marker is refused permanently; material created after it — including the successor a rotation creates — is unaffected. The
detailsays which of the two causes applies. - Indices were spent by signatures that never reached you. An index is committed before signing, so a request that fails after that point — a client abort, a timeout, a timestamp authority failure after signing, a write failure — still consumes one. On a streaming route and on the PKCS#7 conversion the index is spent before the request body is processed, so a request refused for its body (for example a streaming re-sign whose source signature does not verify) consumes one too. Repeated failures drain the key faster than its successful signatures suggest.
Response Example
{
"type": "https://docs.ankatech.co/errors/stateful-key-exhausted",
"title": "Stateful Key Exhausted",
"status": 409,
"detail": "Key 'my-lms-signing-key' cannot produce another signature: every one-time signature it holds has been used. Rotate the key; the signatures it already produced still verify.",
"instance": "/api/v3/crypto/sign",
"correlationId": "3f2b8c1e-6d4a-4f0b-9a7e-2c5d8e1f4a90",
"timestamp": 1768472401,
"extensions": {
"code": "STATEFUL_KEY_EXHAUSTED"
}
}
After a database restore, the detail reads: "Key 'my-lms-signing-key' cannot produce another signature: it existed in a database that was later restored, so its one-time signature state may already have been used. Rotate the key; the signatures it already produced still verify."
Content-Type: application/problem+json — the response follows RFC 9457 Problem Details. There is no Retry-After: retrying cannot succeed.
Where it is answered
The eight operations that sign with a tenant key: POST /api/v3/crypto/sign, /resign and /sign-encrypt; their streaming forms POST /api/v3/crypto/stream/sign, /stream/resign and /stream/sign-encrypt; and POST /api/v3/migration/convert-pkcs7-to-jose and /migration/stream/convert-pkcs7-to-jose. On a streaming operation the refusal is decided before any output exists, so it arrives as this problem document, never as a 200 with a truncated body.
How to Resolve
- Rotate the key, or create a new stateful key, and sign with the new one. Rotation is the only way to sign again under the same kid: the successor material signs from index 0, and the previous material becomes
RETIREDand keeps VERIFY. - Keep the exhausted key for verification. Its earlier signatures stay valid; do not delete it while they need to be verified.
- After a restore, an administrator rotates each stateful key that existed in the restored copy (the restore runbook step). Do not revoke it with the cause
SECURITY_COMPROMISE: lost one-time-signature state is not key exposure, and that cause also refuses verification, so every genuine signature the key made would stop verifying on the platform. - Plan capacity. Choose a parameter set whose capacity exceeds the signatures you expect over the key's life, and rotate before it runs out; a retry loop against a failing dependency spends indices. The capacity of every row is listed in the Simple Algorithms Catalog.
Related: Stateful Key Busy — the retryable refusal of the same keys; Invalid Key State — the key's lifecycle changed under the request. Key semantics: Stateful Hash-Based Signature Keys.