Signature Not Verifiable
URI: https://docs.ankatech.co/errors/signature-not-verifiable
HTTP Status: 422 Unprocessable Entity
When You See This
You asked the platform to re-sign an existing JWS with a composite (hybrid) key, and the signature already on that artifact did not verify against the key you named as its origin. Raised by POST /api/v3/crypto/resign when oldKid refers to a composite key.
Re-signing means: verify what you have, then sign the same payload with the new key. If the first half fails there is nothing to carry forward — the payload's provenance is exactly what the operation was supposed to preserve. The server understood the request perfectly and is refusing it, which is why this is a 422 and not a 500.
Common Causes
-
The artifact was signed with a different key
–oldKidnames a key that never signed this JWS. Two keys in the same tenant are easy to confuse when their kids differ by one segment -
The payload was altered after signing
– Any change to the payload, however small, invalidates the signature. Re-encoding, re-serializing, or a round trip through a system that normalizes whitespace all count -
The artifact was truncated or re-assembled
– A JWS whosepayloadorsignaturemember was cut off during transfer or storage -
One component of a composite signature does not verify
– A composite signature carries two independent signatures (for example Ed25519 and ML-DSA-44) and both must verify. A single failing component fails the whole verification, which is the entire point of the hybrid construction
No Lineage Is Disclosed
The detail field names the kid you supplied and nothing else. It does not say which material version was tried, which component failed, or how many versions of that key exist. A caller able to enumerate a key's version lineage from failed verifications would have an inventory oracle, so the refusal is deliberately uninformative on that axis.
The kid is echoed because you supplied it.
Response Example
{
"type": "https://docs.ankatech.co/errors/signature-not-verifiable",
"title": "Signature Not Verifiable",
"status": 422,
"detail": "Signature verification failed with old key: hybrid-signing-key",
"instance": "/api/v3/crypto/resign",
"correlationId": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": 1738117563
}
Content-Type: application/problem+json — the response follows RFC 9457 Problem Details.
Rotation Is Not a Cause
A common assumption is that this appears after the key has rotated, because the artifact was signed under an earlier material version. It does not. The operative material version travels inside the artifact's own protected header as the ank_kv claim, and the verify leg resolves that version rather than the current PRIMARY — including versions that are RETIRED or REVOKED.
Re-signing a pre-rotation artifact is a supported operation and is in fact the reason re-signing exists. If you are seeing this error after a rotation, the cause is one of the four above, not the rotation.
The one lifecycle state that does refuse is DESTROYED: its key material is gone, so no verification is possible. That refusal is a different problem type.
How to Resolve
Step 1: Confirm Which Key Signed the Artifact
Each entry in the JWS signatures array names its key. Decode that entry's protected member (base64url) and read kid — the unprotected header object usually carries it too:
If that kid differs from the oldKid you sent, send the one from the artifact. A composite signature has two entries in signatures, one per component, and both name the same composite key.
Step 2: Verify Before Re-Signing
Ask the platform directly, which separates "wrong key" from "altered payload":
POST /api/v3/crypto/verify
Content-Type: application/json
{
"jwsToken": {
"payload": "SGVsbG8gQW5rYQ",
"signatures": [
{
"protected": "<protected-b64url>",
"header": {"kid": "hybrid-signing-key"},
"signature": "<signature-b64url>"
}
]
}
}
A failure here on the key from Step 1 means the payload no longer matches its signature — the artifact is not re-signable, and the correct action is to obtain an intact copy, not to retry.
Step 3: Rule Out Transport Damage
If the artifact passed through a system that re-serializes JSON, compare the payload member byte for byte against the source. A JWS signature covers the exact bytes; a semantically equivalent re-encoding is a different artifact.
Related Errors
- Signature Mismatch - The request itself is malformed rather than unverifiable → 400
- Material Version Not Found - The
ank_kvin the artifact names a version this key does not have → 404 - Unprocessable Entity - The generic 422 for other domain refusals on the crypto plane
Streaming Re-Sign Reports This Differently
POST /api/v3/crypto/stream/resign does not return this problem document. A streaming response has already committed its status line before the source signature can be checked against the whole payload, so an unverifiable source is reported as an end-of-stream verdict in the second part of the multipart/mixed body — INVALID with reason SOURCE_SIGNATURE — and the new JWS part is empty.
Treat that verdict as equivalent to this 422. A streaming client that reads only the status line will see success and must read the trailing verdict to learn otherwise.
Need Help?
- Decode the protected header first — it is the fastest way to separate "wrong key" from "altered payload"
- If the key is confirmed correct and the payload is intact, contact support with the
correlationIdfrom the error response