Developer HubAPI Error Troubleshooting
On this page0

Unfamiliar word? See Glossary: words used in these docs. Looking for the tasks in order? Begin at Start Here.

Reference

Not a developer? The step-by-step guides begin at Start Here, and a problem on your screen is in When something goes wrong.

API Error Troubleshooting

The plain explanation is above. This part is for IT and developers: the exact settings, permission names, API addresses and data fields behind it.

What the common failures actually mean, and what to check first. Errors raised through the shared error handler carry a correlationId — quote it to support and we can find the exact log line across the gateway and the service that failed. A few guard refusals (step-up, rate limit, subscription lapsed, cross-site check) carry none; see Error Handling.

This page is a lookup by what you see, and it is not where the meaning of a status number or of a machine-readable code is kept. Each status number is defined once, under Status Codes You’ll See, and each code once, under Error Code Reference. The rows below add only the first thing to check for a particular message; where a row and those tables seem to differ, the tables are right.

Symptom → Cause → Fix

You seeWhat it means and what to do
401 · Authentication context missingYour session did not reach the service. The token is missing or expired — sign in again.
401 · Internal service trust failureThe request did not come through the gateway. If you are calling a service directly, route through the gateway instead.
403 · MFA RequiredThe session is valid but multi-factor has not been satisfied yet. Complete MFA, then retry — this is checked before any permission.
403 · Access DeniedAuthenticated, but missing the permission the route requires. Grant one of the listed permissions. Denials are recorded in the audit log with the permission that was needed.
403 · License RequiredThe feature is not enabled for this deployment’s plan. This is an account-level flag, not something a user can toggle.
400 or 401 · SUDO_REQUIREDA sensitive action needs a fresh re-authentication (password or passkey). A missing or expired step-up is refused with "error": "SUDO_REQUIRED" in the response body. The status beside it is 400 on most routes, because the gateway turns a 401 from a service behind it into 400. It stays 401 on the routes the gateway passes through unchanged: removing a passkey, the diagnostics bundle, and in Security Lab starting an aggressive scan, changing a scan scope and archiving findings. Key on the error string, not the status. Re-authenticate, then repeat the same request. A step-up counts for 15 minutes. The server reads the window from a stored setting, sudoTimeoutMinutes, and holds any value between 1 and 60 minutes, but no screen and no API route writes that setting, so every instance uses 15 minutes. Re-authentication is limited to 5 failed attempts per 15 minutes.
403 · Target is not within an authorized, attested scopeYou are scanning a host outside your declared scopes. Add it to a scope with owner attestation first.
429 on sign-inRate limited: 20 failed authentication attempts per 15 minutes, per client IP; successful sign-ins are not counted. Wait for the window to roll over.
429 on MFARate limited: 20 failed attempts per 5 minutes, per client IP.
423 · MFA_LOCKEDToo many wrong second-factor codes for this account. Wait for the lock to end (15 minutes), then try again with a fresh code. What counts towards the lock is under Error Code Reference and Attempt Limits And Replay Protection.
429 on sign-in link requestsRate limited: 30 requests for an emailed sign-in link per 15 minutes, per client IP. Every request counts, successful or not.
402 · Subscription lapsedThe subscription has lapsed, so plan-gated modules are paused until it is renewed. Your data and core features stay available. See License Administration.
403 · CSRF check failed: missing or untrusted Origin.A write request authenticated with the session cookie did not carry a trusted Origin header. From a script, authenticate with a personal API token in the Authorization header instead, or send your instance’s own address as Origin.
424 on an email test or an invitationYour mail server refused the message. The response carries the mail server’s own reason (wrong sign-in, TLS, or host). Fix the settings under Security Settings → Email / SMTP; see the Set up email guide.
410 · expired governance requestA dangerous-toggle request sat unapproved for more than 24 hours and was discarded. Start the confirm-phrase ceremony again.
Drift scan returns connected: false and zerosNo identity hook is both active and verified, and no CSV source is loaded — there is nothing to compare against yet. Connect and validate a hook, or upload a source file.
409 · blast_radius_exceededThe bulk change would touch a larger share of the directory than your cap allows. Split it into smaller batches, or re-send with override if it is intentional.
409 · cannot approve your own change requestSeparation of duties. A different privileged user has to approve it.
Scan finished but the score is nullNo findings have ever been recorded. Confirm the scan actually reached completed and that probes ran — null means “never scanned,” not “clean.”
A hook saves but never syncsBackground sync only runs once a hook is verified and active, and only after its interval has elapsed. Run a manual sync to confirm the credentials work.
410 · Gone, on provisioning statusThe instance is still polling GET /api/service/provision/status/:id?t=…. That form was removed — the retrieval token must not travel in a URL. Switch to POST on the same path with { "retrievalToken": "…" } in the JSON body.
401 · Unauthorized status checkThe retrieval token is wrong, or — far more likely — it has already been spent. It is single-use and is destroyed the moment the license secret is handed back, so a second poll after activation always fails. If the secret was not persisted on that first response, re-provision with a fresh provisioning key.
403 · Stale heartbeat timestampThis heartbeat’s timestamp is not newer than the last one accepted for the license — usually a retry that re-sent a cached, already-delivered payload, or a clock that stepped backwards. Re-sign every retry with a fresh timestamp and keep NTP running.
403 · Request expired (CLOCK_SKEW)The heartbeat timestamp is more than 5 minutes from store time. This is clock drift on your server, not a network problem; the response’s serverTime shows how far off it is. The server’s clock has to be corrected (NTP).
403 · Invalid signature after adding telemetryThe signed array must carry all ten fields, with absent telemetry as null rather than omitted, and metrics must serialise with the same key order in the signature and the body. See License Verification.

Why 5xx Errors Say So Little

Client errors (4xx) return a real message and a machine-readable code so your integration can branch on it. Server errors (5xx) are deliberately genericised to Internal Server Error in production so nothing internal leaks to the caller — the full detail is in your instance’s logs under the same correlationId. Through the shared error handler a code is attached only below 500. A reply that the gateway or a service builds itself can carry one on a 5xx: 503 STILL_RUNNING is the one you are most likely to meet, and the Error Handling table lists the others with their status.

One deliberate quirk worth knowing: if a connected provider (Azure, Okta…) rejects its own stored credentials with a 401, Zonitix returns that to you as a 400, not a 401 — so your UI never mistakes an expired provider secret for your own session expiring.

Related reference