deviceNotSupported | Physical device doesn’t support App Attest (old hardware or restricted region) | Degrade gracefully; this is a permanent device limitation |
simulatorAPIKeyRequired | validateAttestation() called in the iOS Simulator without an API key configured | Initialize with Grantiva(teamId:apiKey:) — see Simulator Setup |
attestationNotAvailable | App Attest not supported in this region | Degrade gracefully |
networkError(Error) | Network communication failed | Retry with backoff |
validationFailed | Server rejected the attestation | Device may be compromised — block or challenge |
tokenExpired | JWT token has expired | Call refreshToken() or validateAttestation() |
configurationError | Invalid Bundle ID or Team ID | Check SDK initialization |
keyGenerationFailed | Can’t create attestation key | Retry; may indicate Keychain issue |
challengeExpired | Server challenge timed out | Retry — the SDK handles this automatically |
invalidResponse | Unexpected server response format | Check SDK/server version compatibility |
rateLimited | Too many requests | Back off and retry after delay |
feedbackNotAvailable | Feedback not enabled for this tenant | Check your plan includes feedback |
reattestRequired | Server reports attestation key has drifted (rpIdHash or signature mismatch) | The SDK self-heals: it clears the cached keyId and re-runs attestation automatically. Avoid wrapping SDK calls in retry loops that re-call validateAttestation() — the SDK already retries once internally |
serverError(reason: String) | Server-side validation failure with a developer-readable reason | Log error.reason for diagnostics; do not show the raw reason to end users |
keyAlreadyAttested | Apple’s DCAppAttestService rejected attestKey because the keyId was already attested in a prior session | The SDK self-heals by clearing the stored keyId and generating a fresh one. If the retry also fails, this error surfaces to the caller — typically after a re-install or Keychain wipe |