Errors and retries
Exception hierarchy, what each one means, and the retry strategy you actually want.
Exception tree
Both SDKs share the same conceptual hierarchy.
Python
SharkAuthError
├── DPoPError # constructing or signing DPoP proof
├── DeviceFlowError # RFC 8628 errors
├── VaultError # vault HTTP failures (status_code attr)
├── TokenError # decoding / verifying agent JWTs
├── OAuthError # OAuth token endpoint 4xx/5xx (RFC 6749 fields)
└── SharkAPIError # generic admin-API failures (code, status attrs)
TypeScript
SharkAuthError
├── DPoPError
├── DeviceFlowError
├── VaultError
├── TokenError
└── SharkAPIError # admin-API failures
The TypeScript SDK does not yet export a dedicated OAuthError type — TokenError covers the token-endpoint cases. (Parity gap; tracked in sdk/HANDOFF.md.)
OAuthError fields (Python)
VaultError fields
SharkAPIError fields
Retry strategy
The SDKs do not retry automatically (except VaultClient.exchange / fetch_token via the onRefresh callback in TypeScript). You decide.
What to retry
| Status | Retry? | How |
|---|---|---|
| 200 / 2xx | n/a | - |
| 400 | No | Caller bug |
| 401 | Yes (once) | Refresh token, retry |
| 403 | No | Missing scope / wrong principal |
| 404 | No | Resource gone |
| 409 | Maybe | Idempotent operation? Re-fetch state |
| 422 | No | Validation error |
| 429 | Yes (with backoff) | Honor Retry-After |
| 5xx | Yes (with backoff) | Exponential, capped at ~3 attempts |
| Network | Yes (with backoff) | Same |
Backoff
A reasonable default: exponential with jitter, capped.
What not to retry
- Token revocation (
oauth.revoke_token) — server returns 200 even if token didn't exist; failures are network-only and OK to retry. - Audit purge — guard with
dry_run=Truefirst. - DPoP key rotation — irreversible.
- Webhook test fire — duplicates are fine, but pile up in delivery logs.
DPoP-specific failures
DPoPError from make_proof / createProof usually means one of:
- The keypair is malformed (caller passed a non-P-256 PEM).
htuURL is malformed.- Signing failed in Web Crypto (TypeScript) — typically permission/CSP issue in a browser.
All four cases are programmer error, not transient — do not retry.
Surfacing errors to users
The server returns RFC 6749 / 7807 style bodies:
The SDK lifts these into the exception message. Log error_description (when present) — it's the user-facing copy.
See also
- DPoP —
DPoPErrorcauses - Token exchange — common
OAuthErrorcodes - Vault — 401/403/404 paths