Skip to content

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:

  1. 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.
  2. Wrong signed string. It is "{timestamp}.{body}" (timestamp, a dot, the body), with the X-HodeiShield-Timestamp value of the same attempt: every retry is re-signed with a new timestamp.
  3. You compare without the sha256= prefix: the value of X-HodeiShield-Signature-256 includes it.
  4. You verify the legacy header X-HodeiShield-Signature with the new scheme (or the other way round). They are two different schemes; use X-HodeiShield-Signature-256.
  5. Wrong or rotated secret. The secret (whsec_…) is shown once; if you lost or rotated it, use the new one.
  6. 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