Troubleshooting¶
Each entry gives the symptom, the cause and the fix. Every /v1 error carries a request_id
(also in the X-Request-Id header): quote it if you contact support.
API¶
| Symptom | Cause | Fix |
|---|---|---|
401 unauthorized |
Unknown, malformed, revoked or expired key: the answer is the same for all four | Check you send the whole Authorization: Bearer <credential>; if the key was revoked or expired, create a new one (or rotate the existing one) in the console. See Authentication |
403 forbidden, with details.missing |
The credential lacks a scope | Create a key with the scope details.missing names. No scope implies another, and compliance is per framework |
403 with details.code: "LICENCE_INACTIVE" |
Your tenant has no licence in force (none, suspended, revoked or expired; details.licence says which) |
A new token does not fix it: a tenant administrator must renew or reactivate the licence in the console |
400 with details.code: "TENANT_REQUIRED" |
You use a portfolio (MSSP) key without the X-HS-Tenant header |
Send X-HS-Tenant: <tenant id> (a UUID, never a slug). GET /v1/portfolio/tenants lists the ones you can select |
400 with details.code: "TENANT_SELECTOR_NOT_SUPPORTED" |
A tenant key or OAuth token sent X-HS-Tenant with an id that is not its own tenant's |
Drop the header or send your own tenant's id |
400 with details.code: "TENANT_HEADER_INVALID" |
X-HS-Tenant is not a valid UUID |
Use the tenant id (a UUID) |
404 with details.code: "TENANT_NOT_FOUND" |
The tenant is not in the key's portfolio, or does not exist: the answer is the same | Check the id with GET /v1/portfolio/tenants |
405 method_not_allowed |
/v1 is read-only: any method other than GET is refused |
Use GET; the Allow header says so |
409 with details.code: "REPORT_NOT_READY" |
The report is still being generated or failed (details.status) |
If details.status is generating, retry later |
409 with details.code: "FORMAT_UNSUPPORTED" |
There is no renderer for the requested format | Pick one of details.formats |
429 rate_limited |
You exceeded a rate limit (details.scope says which) |
Wait what Retry-After says and retry with backoff. See Rate limits |
The full vocabulary is in Errors.
Webhooks¶
Signature verification fails. Usual causes, most frequent first:
- You compute the HMAC over a body other than the one sent. The signature covers the body exactly as it arrives; if your framework parses and re-serialises it before you verify, the bytes change. Verify over the raw body.
- Wrong signed string. It is
"{timestamp}.{body}"(timestamp, a dot, the body), with theX-HodeiShield-Timestampvalue of the same attempt: every retry is re-signed with a new timestamp. - You compare without the
sha256=prefix: the value ofX-HodeiShield-Signature-256includes it. - You verify the legacy header
X-HodeiShield-Signaturewith the new scheme (or the other way round). They are two different schemes; useX-HodeiShield-Signature-256. - Wrong or rotated secret. The secret (
whsec_…) is shown once; if you lost or rotated it, use the new one. - Timestamp outside tolerance. We recommend rejecting those more than 5 minutes away from your clock; if your server's clock drifts, synchronise it.
The signature headers do not arrive. The signature headers are only sent when the webhook has a secret configured.
You receive the same delivery twice. Expected on a retry (at-least-once delivery).
Deduplicate on X-HodeiShield-Delivery, identical across every retry.
A delivery shows as failed. After six attempts without a 2xx answer (at 5 minutes,
30 minutes, 2 hours, 6 hours and 24 hours) it is marked failed; fix your endpoint and requeue
it from the console. See Webhooks.
CLI¶
The CLI reports the result with its exit code (full table in CLI).
| Symptom | Cause | Fix |
|---|---|---|
Exit 3 on a server, container or CI; login stops before opening the browser |
There is no system keychain (or it is not reachable in that session) | Use a tenant API key in HODEISHIELD_API_KEY; it is the recommended option for servers, containers and CI |
| Exit 3 with the key set | The API rejected the credential: revoked, expired or wrong key | Create or rotate the key. If you use a portfolio key with a source IP restriction, a request from another address is refused like an unknown key |
| Exit 4 | The credential lacks the scope the command needs | Create a key with that scope |
| Exit 6 | Rate limit exhausted (the CLI already retried short waits) | Wait and repeat; see Rate limits |
| Exit 8 | The tenant's licence is not in force | An administrator must renew or reactivate it |
login and logout exit 1 on a machine without a keychain |
The CLI does not fall back to a file on its own | Use HODEISHIELD_API_KEY. Keeping the session in a plain-text file is an explicit opt-in with risks, explained on the CLI page |