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.
Error Handling
What It Does
When something goes wrong, the API tells you what in a stable shape and hands back a correlation ID you can quote to support to find the exact log line. Client mistakes (a bad field, a missing permission) come back with a clear message; genuine server faults are deliberately kept vague to the caller so nothing sensitive leaks — the full detail is in your instance’s logs.
Many refusals also carry a short machine-readable code, so software calling the API can react correctly without reading the sentence: wait, ask the person to sign in again, or show an upgrade prompt. The full list is at the end of this page.
The plain explanation is above. This part is for IT and developers: the exact settings, permission names, API addresses and data fields behind it.
Errors raised through the shared error handler come back in one envelope, so your integration can branch on structure instead of parsing prose. A few refusals issued by guards in front of the handler use a simpler shape; they are listed below.
The Error Envelope
// Shape returned by the shared error handler:
{
"error": "Human-readable message (4xx) or 'Internal Server Error' (5xx in prod)",
"code": "MACHINE_CODE", // only present below 500 — lets the UI branch
"correlationId": "a1b2c3…" // quote this to support to find the log line
// "stack" is included only outside production
}
erroris always a string. When a connected vendor answers with an error object, the handler flattens it to its message before replying.codeis included only below 500. A server fault never carries one through this handler.- The gateway generates the correlation ID for every request and returns it in the
x-correlation-idresponse header, on success and failure alike; a value sent by the client is discarded. The one reply without the header is the cross-site request check refusal below, which is answered before a correlation ID is assigned. - A 401 from a connected vendor (a rejected directory credential, for example) is returned to you as 400, so it cannot be mistaken for your own session expiring.
- An unknown path answers
404 { "error": "Not found" }as JSON, with nocorrelationIdin the body.
Refusals That Do Not Use The Envelope
Guards that run in front of the handler, and controllers that reply directly, send smaller bodies. None of these has a correlationId in the body; read the x-correlation-id response header instead (the cross-site request check refusal has neither).
- Direct controller reply:
{ "error": "…", "code": "MACHINE_CODE" }. Most coded refusals in the table below are sent this way, and a few add fields of their own (missing,conflicts,replacement). - Step-up required:
{ "error": "SUDO_REQUIRED", "message": "This action requires re-authentication" }. The machine code is inerrorand there is nocode. Where the gateway forwards the call itself and answers through the shared error handler,messageis replaced by acorrelationId. 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. - Session not valid:
401 { "auth": false, "message": "Session invalid or expired" }, passed through from session validation. There is amessageand noerror. When the account itself is no longer active the gateway addserrorand"code": "SESSION_NOT_ACTIVE". - Second factor not completed:
403 { "error": "MFA Required", "message": "Multi-Factor Authentication is required to perform this action." }. - Rate limits:
429 { "error": "Too many authentication attempts. Please try again later." }— anerrorstring only. - Subscription lapsed:
402 { "error": "Subscription lapsed", "message": "…" }. - Not in your plan:
403 { "error": "License Required", "message": "…" }. - Cross-site request check:
403 { "error": "CSRF check failed: missing or untrusted Origin." }, for a cookie-authenticated write with no trustedOrigin. This reply carries nox-correlation-idheader. - Network or location block:
403 { "error": "Access denied." }, with no further detail by design. - Read-only support session:
403 { "error": "Support session is read-only", "message": "…" }. - Finance endpoints: the finance service answers its own validation and conflict errors as
{ "detail": "…" }, and the gateway forwards that body unchanged. Its guards (request too large, subscription lapsed, not in your plan) use{ "error": "…", "message": "…" }. - SCIM endpoints: errors use the SCIM error schema,
{ "schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"], "status": "429", "detail": "…" }, withscimTypewhere the standard defines one.
A client that handles all of these reads the status first, then code, then a machine word in error, and shows whichever of error, message or detail is present.
Status Codes You’ll See
This table is the one place the meaning of each status number is kept, and the Error Code Reference at the end of this page is the one place for each machine-readable code. Other pages link here. To look a failure up by the message you received, use API Error Troubleshooting.
| Status | Meaning |
|---|---|
| 400 | Validation error — a field is missing or malformed. The message names the problem; several problems are joined with a semicolon. Also what a connected vendor’s own 401 is turned into, and what any 401 raised by a service behind the gateway is turned into (except on the SCIM and device-agent endpoints). 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. |
| 401 | Not authenticated — missing or invalid session or API token (including a revoked or expired token), a session that is no longer active, or a request that didn’t come through the trusted gateway. A step-up refusal is 401 only on the pass-through routes named in the 400 row above. |
| 402 | Subscription lapsed — plan-gated modules are paused until it is renewed; your data and core features stay available (see License Administration). |
| 403 | Authenticated but not allowed — multi-factor authentication has not been completed for this session (MFA Required, checked before any permission), you lack the permission, the feature isn’t in your plan (License Required), the request failed the cross-site check, the network or location is blocked, or a read-only support session tried to write. |
| 404 | No such resource, or it’s outside your scope. An unknown path answers the same way, as JSON. |
| 405 | A write method on the read-only training content endpoints. |
| 409 | Conflict with the current state — for example a request that is already pending, a record that changed since you loaded it, or a step taken out of order. The most common status behind a code. |
| 410 | Gone for good. Either a retired endpoint whose body names the replacement (the legacy compliance attestation writes and the compliance digest), or a one-time or expiring link that has been used, expired, cancelled or revoked (signing, interview scheduling, candidate portal, export download, shared report, setup key). |
| 413 | Too large — an uploaded file over the limit for that upload, an over-long CSV import or device profile, or a finance request body over its limit. |
| 416 | A byte range that cannot be served, on training media. The body is empty. |
| 422 | Understood but cannot be carried out as sent — a device command the device’s platform does not support, or an offer letter containing a script the document font cannot render (code: OFFER_LETTER_UNSUPPORTED_SCRIPT). |
| 423 | Temporarily locked — too many wrong second-factor codes; the account is locked for 15 minutes (code: MFA_LOCKED). |
| 424 | Something this request depends on refused — the mail server rejected a test or an invitation, the identity provider could not be reached for single sign-on, or the device management server did not answer. The body carries the reason. |
| 429 | Rate limited — back off and retry (see Rate, Size & Time Limits). A personal API token is limited to 300 requests per minute; the RateLimit-* response headers say when to retry. Also used for a daily cap, a locked signing link and throttled setup attempts. |
| 501 | A directory action that is not implemented for the connected provider type. The message names the provider type; some replies also carry it in providerType. |
| 502 | An upstream the request needed failed, and the message says which — for example a drafting assistant that could not produce text, or a device management server that did not confirm a command. |
| 503 | The instance cannot do this right now, and says why when the reply is sent directly: the sign-in service or a service behind the gateway is unavailable, rate limiting itself is unavailable, setup state cannot be read, or a long-running request is still working (code: STILL_RUNNING). Safe to retry after a pause, except STILL_RUNNING, which must not be sent again (see Retries below). |
| 504 | The gateway could not get an answer from the service behind it (Gateway Timeout): the service could not be reached, dropped the connection, or took longer than the gateway waits, which is 300 seconds by default. A write may or may not have been applied. |
| 5xx | Other server faults — through the shared handler the message is genericized to Internal Server Error in production, whatever the status; the real detail is logged with the correlation ID. |
A plan refusal carries no code. Tell “not in your plan” from “broken” by the status and the fixed error string — 402 with Subscription lapsed, 403 with License Required — so your UI can prompt a renewal or an upgrade instead of showing a generic failure.
Retry-After And Rate-Limit Headers
Three replies set Retry-After (in seconds) themselves. Honour it rather than retrying on a fixed timer.
| Reply | Retry-After | What it means |
|---|---|---|
| 503 STILL_RUNNING | 60 | A long-running request is still working on the server. Do not send it again — that would start the work a second time. Read the result after the interval. |
| 503, rate limiting unavailable | 5 | The store behind the rate limits cannot be reached, so the endpoints those limits protect (sign-in, second factor, step-up, setup, public submissions and others) refuse requests rather than let them through unprotected. Retry the same request after the interval. |
| 429, public recruitment endpoints | seconds left in the window | Too many requests from one address to the careers site, application, candidate portal or scheduling endpoints. Never less than 1. |
The gateway’s own rate limits answer 429 with the standard RateLimit-* response headers and without the older X-RateLimit-* ones. Read RateLimit-Reset for when to try again. The second-factor limiter, which guards the /auth/mfa/* routes and the passkey registration and sign-in routes under /auth/webauthn/*, is the exception: its configuration does not select a header set, so do not rely on RateLimit-Reset on those routes. Its window is 5 minutes; after a 429 there, wait up to 5 minutes. The body is an error sentence with no code; on the SCIM endpoints it is a SCIM error body.
Retries: What Is Safe To Send Again
In plain words: reading something twice is harmless; creating something twice can leave you with two of it. The API does not recognise a repeated request by itself, so your script has to know which requests it may repeat.
- GET and HEAD are safe to repeat. They do not change your records. Repeat them after any error or timeout.
- PUT is safe to repeat with the same body. A PUT replaces a record or a setting with what you send, so sending it twice ends in the same state. The API adds nothing of its own to guarantee this; it follows from the method.
- DELETE is normally safe to repeat. Once the record is gone there is nothing left to remove. The status of the second call differs by route (often 404); treat any 4xx on the repeat as already done and confirm with a read.
- POST is not deduplicated. Unless a route’s own entry says it accepts an idempotency key, none is read, so a POST that is sent twice is handled twice. If a POST times out, read back before sending it again. Treat PATCH the same way unless its entry says it only sets fields to the values you send.
What 409 means
409 says the request was understood and not applied, because it conflicts with what is already there. The same request keeps getting 409 until that state changes, so do not retry it on a timer. Three cases come up most:
- It already exists. Creating a user whose email is taken, or a role whose name is taken, answers 409. After a create that timed out, a 409 on the second attempt usually means the first one went through: read the record to confirm.
- Something is already in progress. Update, backup, restore and backup-deletion requests share one pending slot. A second request while one is waiting for approval or running answers 409. Wait for it to finish, or have it rejected or cancelled (see Backup, Restore & Updates).
- The record changed or the step is out of order. Reload the record and decide again. Many of these carry a
code; the table at the end of this page says what each one needs.
Three POST routes whose repeat is known
- Creating a SCIM user twice.
POST /scim/v2/Usersfor an address that a live account already has answers 409 withscimTypeuniqueness. Nothing is created the second time. - Marking notifications read.
POST /user-management/notifications/:id/readand/read-allonly touch notifications that are still unread, so repeating either changes nothing. - Confirming an authenticator app twice. A second
POST /auth/mfa/setup/confirmwith a valid code is accepted. Recovery codes are issued only when the account has none, so the repeat answersrecoveryCodes: null: keep the codes from the first reply.
In the API reference, many write rows say in their guard line what a repeat does, after the word Repeat. Not every write row carries one.
By status
| Reply | Send again? | Why |
|---|---|---|
| 429 | Yes, after waiting | The request was counted and refused. Wait for the time in RateLimit-Reset or Retry-After, then send the same request. |
| 503 with Retry-After: 5 | Yes, any method | Rate limiting itself was unavailable and the request was refused in front of the route. Nothing ran. |
| 503 "Service temporarily unavailable" | Yes, any method | The gateway did not call the service. Nothing ran. Wait a few seconds: the gateway forwards requests to the service again after 15 seconds. |
| 503 "Auth service unavailable" | Yes, any method | The session or token could not be checked, so the request was not forwarded. |
| 503 "Internal Server Error" | Reads yes; writes check first | Sent by a route the gateway serves by calling a service itself (for example Security Lab). In production the message is generic, so the reply does not say whether the service was called. Read the record back before repeating a write. |
| 503 STILL_RUNNING | No | The work started and is still running. Sending it again starts it a second time. Read the result after Retry-After. |
| 504 "Gateway Timeout" | Reads yes; writes check first | The gateway lost the service part-way. A write may have been applied. Read the record back before sending it again. |
| 500 | Reads yes; writes check first | The service failed while handling the request. Quote the correlationId if it keeps happening. |
| 400, 401, 403, 404, 409, 410, 413, 422 | No, not unchanged | The same request will get the same answer. Change the request, the credentials or the state it depends on first. |
Set your client’s own timeout with the gateway’s in mind: by default it waits up to 300 seconds for a service before answering 504. A client that gives up sooner cannot tell whether a write was applied, and should read back before repeating it. What each outage looks like is on Failure Modes.
Error Code Reference
The machine-readable words the API puts in an error body, grouped by subject. Unless a row says otherwise the word is the value of code. Rows marked “in error” carry it in the error field and have no code. Branch on the status together with the word: a few words are reused by different services.
Authentication and session
Answers about who is calling. A 401 here means the session or token is no longer usable; sign in again rather than retrying.
| Code | Status | Sent by | When | What to do |
|---|---|---|---|---|
| No token providedin error | 401 | Gateway | The request carried neither a session cookie nor an Authorization header. | Send the session cookie or a Bearer token. |
| Invalid tokenin error | 401 | Gateway | The token could not be verified. | Sign in again, or replace the API token. |
| SESSION_NOT_ACTIVE | 401 | Gateway | Session validation found the account deactivated or offboarded, or a support grant revoked or expired. The body also carries "auth": false. | Treat as signed out. Do not retry with the same session. |
| SESSION_REVOKED | 400 or 401 | Identity service | During a second-factor, passkey or forced password-change step: the session was signed out or invalidated, or the password-change link was already used. The status is 401 on the password-change route, on passkey step-up and on passkey removal, and 400 on the second-factor routes and on the passkey registration and second-factor passkey routes. | Start sign-in again from the beginning. |
| ACCOUNT_BLOCKED | 403 | Identity service | During the same steps: the account is not active. | Stop. An administrator must reactivate the account. |
| NO_CHANGE_PENDING | 409 | Identity service | A forced password change was submitted but none is pending for the account. | Sign in again. |
| SESSION_REQUIRED | 403 | Identity service | An API token was used to list, create or revoke API tokens. | Manage tokens from a signed-in browser session. |
| MFA_REQUIRED_FOR_API_TOKENS | 403 | Identity service | The account creating a token has no verified multi-factor authentication. | Enrol and verify a second factor, then create the token. |
| SCOPE_EXCEEDS_OWNER | 400 | Identity service | A token was requested with a permission its owner does not hold. | Request only permissions the owner has. |
Step-up (re-authentication)
A sensitive action needs a recent re-authentication. The step-up refusal puts its machine word in "error", not "code".
| Code | Status | Sent by | When | What to do |
|---|---|---|---|---|
| SUDO_REQUIREDin error | 400 or 401 | Shared middleware; Security Lab service | The action needs a step-up and the session has none, or it is too old. 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. 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-authenticate (password or passkey), then repeat the same request. |
| NO_PASSKEYin error | 404 | Identity service | A passkey step-up was requested but the account has no passkey. | Fall back to the password step-up. |
| NO_LOCAL_PASSWORD | 400 | Identity service | A password step-up was refused for an account that signs in through an identity provider and normally has no local password. | Use a passkey for step-up; add one under Account Security first. |
| ASSERTION_NOT_VERIFIED | 400 | Identity service | The passkey response for a step-up did not verify. | Try the passkey again, or confirm with the password. |
Multi-factor authentication
Returned while completing or changing a second factor.
| Code | Status | Sent by | When | What to do |
|---|---|---|---|---|
| MFA Requiredin error | 403 | Gateway | The session has not completed its second factor. Checked before any permission, on every authenticated route except /auth/me and /auth/refresh. | Complete the second factor, then repeat the request. |
| MFA_SESSION_EXPIRED | 400 | Identity service | The short-lived verification session expired, or too many incorrect codes were entered in it. | Sign in with the password again. |
| MFA_LOCKED | 423 | Identity service | Too many failed second-factor attempts. The account is locked for 15 minutes; the message gives the minutes left. | Wait for the lock to end. Retrying earlier does not help. |
| MFA_VERIFICATION_REQUIRED | 403 | Identity service | A factor was added, removed or recovery codes regenerated on an account that already has a factor, from a session that has not passed it. | Verify with an existing factor first. |
| TOTP_REPLAY | 400 | Identity service | The authenticator code was already used. | Wait for the next code. |
| NO_TOTP_ENROLLED | 400 | Identity service | An authenticator code was submitted for an account with no authenticator app enrolled. | Use a passkey or a recovery code. |
| UNKNOWN_PASSKEY | 401 | Identity service | The passkey presented is not registered. | Sign in with the password, or enrol the passkey first. |
| LAST_FACTOR | 409 | Identity service | Removing this passkey would leave the account with no second factor. | Add another passkey or an authenticator app, then remove it. |
Rate limiting and availability
Gateway rate limits answer 429 with an "error" sentence and no code. The rows below are the limits and waits that do carry one.
| Code | Status | Sent by | When | What to do |
|---|---|---|---|---|
| STILL_RUNNING | 503 | Gateway | A long-running request (a Security Lab scan or re-test, a cloud resource read or invoice sync) outlived the time the request can wait. The work continues on the server. Sent with Retry-After: 60. | Do not resend. Read the result after the Retry-After interval. |
| EXPORT_RATE_LIMITED | 429 | Compliance service | The daily cap on full data exports was reached. | Try again later; the message states the cap. |
| ACCESS_LOCKED | 429 | Signature service | Too many wrong access codes on a signing link. The link is locked. | Stop. The sender must issue a new link. |
Licence and plan
Plan refusals carry no "code". Match on the status and the fixed "error" string.
| Code | Status | Sent by | When | What to do |
|---|---|---|---|---|
| Subscription lapsedin error | 402 | Shared middleware; Finance service | The subscription has lapsed past its grace period. Plan-gated modules are paused; data and core features stay available. | Renew the subscription. Do not retry until then. |
| License Requiredin error | 403 | Shared middleware; Finance service | The feature is not included in the current plan. | Show an upgrade prompt rather than a failure. |
Validation
Most validation failures are a plain 400 with a sentence naming the field. These are the ones that also carry a code.
| Code | Status | Sent by | When | What to do |
|---|---|---|---|---|
| PASSWORD_REUSED | 400 | Identity service | The new password matches a recent one (password history). | Choose a password not used recently. The change link stays valid. |
| INVALID_NUMBER | 400 | Recruitment service | A requisition field that must be a whole number was not. | Send a whole number. |
| INVALID_TIME | 400 | Recruitment service | An interview date and time was missing or not a valid date. | Send a valid date and time. |
| INVALID_SCORE | 400 | Recruitment service | An interview score was not a number from 1 to 5. | Send a score from 1 to 5. |
| BAD_URL | 400 | Recruitment service | The careers-site LinkedIn link was not a full https:// address. | Send a full https:// address. |
| BAD_PRIVACY_CONTACT | 400 | Recruitment service | The careers-site privacy contact was neither an email address nor a full https:// link. | Send an email address or an https:// link. |
| BAD_EMAIL | 400 | Recruitment service | A job-alert sign-up had an invalid email address. | Correct the address. |
| CSV_CONFIRM_REQUIRED | 400 | Compliance service | A report share asked for the raw CSV without the explicit confirmation. | Resend with confirmCsv: true once the user has confirmed. |
| NA_JUSTIFICATION_REQUIRED | 400 | Compliance service | A control was marked Not Applicable without a justification. | Send the justification. |
| ADMINISTRATOR_ACK_REQUIRED | 400 | User management service | A support-access grant asked for the administrator role without confirming the warning. | Show the warning and resend with the confirmation. |
First-run setup
The setup endpoints are public until setup completes, so they are throttled and say little.
| Code | Status | Sent by | When | What to do |
|---|---|---|---|---|
| SETUP_KEY_NOT_CONFIGURED | 409 | Identity service | The installation has no setup key configured, so first-run setup is locked. | Contact your provider. Retrying cannot succeed. |
| Invalid setup key.in error | 401 | Identity service | The setup key was wrong. An expired key answers 410 instead. | Re-enter the key. Repeated failures are throttled with 429. |
| Setup status unavailablein error | 503 | Identity service | The server could not read whether setup has completed. | Retry shortly. |
Files, uploads and downloads
An oversized upload is a 413 with a sentence and no code. These rows are the file refusals that carry one.
| Code | Status | Sent by | When | What to do |
|---|---|---|---|---|
| RESUME_TYPE_UNSUPPORTED | 400 | Recruitment service | A résumé upload was not a supported file type. | Upload a PDF or DOCX file. |
| OFFER_LETTER_UNSUPPORTED_SCRIPT | 422 | Recruitment service | The offer letter contains text in a script the document font cannot render. | Use Latin characters in the name, title, company name and template. |
| EXPORT_IN_PROGRESS | 409 | Compliance service | A full data export is already running. | Wait for it to finish. |
| EXPORT_EXPIRED | 410 | Compliance service | The export is no longer available, or its file is no longer on the server. | Create a new export. |
| LINK_USED_OR_EXPIRED | 410 | Compliance service | The one-time export download link was already used or has expired. | Issue a new download link. |
| NO_ENCRYPTION_KEY | 503 | Compliance service | An export could not start because the server has no usable encryption key. | An administrator must fix the server configuration. |
| NOT_SEALED | 404 | Signature service | The signed document was requested before it exists. | Retry after signing completes. |
| NOT_COMPLETED | 409 | Signature service | A signer asked for their signed copy before the document was completed. | Retry after signing completes. |
Recruitment: offers and approvals
Offer state is enforced on the server; a 409 means the offer is not in the state the action needs.
| Code | Status | Sent by | When | What to do |
|---|---|---|---|---|
| OFFER_NOT_FOUND | 404 | Recruitment service | The candidate has no offer for this action. | Set the offer terms first. |
| OFFER_TERMS_MISSING | 400 | Recruitment service | The offer has no start date (or salary where one applies). | Set the terms, then approve. |
| OFFER_TERMS_CHANGED | 409 | Recruitment service | The terms changed after the approver opened the offer. | Reload the current terms and decide again. |
| OFFER_NOT_APPROVED | 409 | Recruitment service | An offer was marked signed before it was approved. | Approve it first. |
| OFFER_ALREADY_SENT | 409 | Recruitment service | Approval was withheld on an offer that is no longer a draft. | Withdraw the offer instead. |
| OFFER_TERMINAL | 409 | Recruitment service | The offer is already in a final state and cannot be re-sent or marked signed. | No retry. Start a new offer if needed. |
| OFFER_NOT_WITHDRAWABLE | 409 | Recruitment service | The offer is in a state that cannot be withdrawn; the message says why. | Follow the message. |
| OFFER_NOT_SIGNED | 409 | Recruitment service | A candidate was moved to Hired while their offer is unsigned. | Wait for the signature, or withdraw the offer first. |
| OFFER_IN_FLIGHT | 409 | Recruitment service | A stage move was refused because an offer is out for signature. | Withdraw the offer first, then move the candidate. |
| SIGNED_OFFER_USE_RESCIND | 409 | Recruitment service | A stage move was refused because the offer is already signed. | Use the rescission flow. |
| NOT_SIGNED | 409 | Recruitment service | A rescission was requested for an offer the candidate has not signed. | Withdraw the offer instead. |
| ALREADY_REQUESTED | 409 | Recruitment service | A rescission is already pending approval. | Approve or wait for the pending one. |
| NOT_REQUESTED | 409 | Recruitment service | A rescission approval was sent but none is pending. | Reload the offer. |
| REASON_REQUIRED | 400 | Recruitment service | A rescission request or a budget refusal had no reason. | Send a reason. |
| SELF_APPROVAL | 403 | Recruitment service | The person who set the terms or requested the rescission tried to approve it. Not returned to a holder of the administrator role. | A second approver must decide. |
| CANDIDATE_REJECTED | 409 | Recruitment service | An offer approval was sent for a rejected candidate. | No retry. |
| SCORECARDS_MISSING | 409 | Recruitment service | An offer action was blocked because interview scorecards are outstanding. The body lists them in "missing". | Collect the scorecards, or cancel interviews that will not happen. |
| APPROVER_UNIDENTIFIED | 403 | Recruitment service | An approval or rejection arrived without an identifiable approver. | Call as a signed-in user. |
| UNIDENTIFIED_APPROVER | 403 | Recruitment service | A rescission approval arrived without an identifiable approver. | Call as a signed-in user. |
| UNIDENTIFIED_ACTOR | 403 | Recruitment service | A rescission request arrived without an identifiable requester. | Call as a signed-in user. |
| ACTOR_UNIDENTIFIED | 403 | Recruitment service | An offer was marked signed without an identifiable caller. | Call as a signed-in user. |
| PORTAL_CLOSED | 410 | Recruitment service | The candidate portal link is closed for this action. | The candidate should contact the recruiter. |
Recruitment: interviews and scheduling
Several of these are returned to a candidate using a scheduling link, not to a signed-in user.
| Code | Status | Sent by | When | What to do |
|---|---|---|---|---|
| INTERVIEWER_REQUIRED | 400 | Recruitment service | A self-scheduling request named no interviewer. | Send an interviewer. |
| NOT_ENOUGH_SLOTS | 400 | Recruitment service | Fewer than two future time options were proposed. | Propose at least two future times. |
| DOUBLE_BOOKED | 409 | Recruitment service | The interviewer already has an interview in that window. The body may list them in "conflicts". | Choose other times, or allow the overlap. |
| INTERVIEWER_NO_ACCESS | 409 | Recruitment service | The chosen interviewer lacks the permission to submit interview scorecards. | Grant the permission, or choose another interviewer. |
| INVALID_TOKEN | 404 | Recruitment service | The scheduling link is not valid. | The candidate should contact the recruiter. |
| ALREADY_SCHEDULED | 409 / 410 | Recruitment service | The interview was already scheduled: 410 when the link is opened, 409 when a time is submitted. | Show the scheduled time. No retry. |
| CANCELLED | 410 | Recruitment service | The interview behind the link was cancelled. | The candidate should contact the recruiter. |
| CLOSED | 410 | Recruitment service | The scheduling link is no longer active. | The candidate should contact the recruiter. |
| SLOTS_EXPIRED | 410 | Recruitment service | Every proposed time has passed. | The recruiter must propose new times. |
| SLOT_NOT_OFFERED | 400 | Recruitment service | The submitted time is not one of the offered options. | Submit one of the offered times. |
| SLOT_PAST | 409 | Recruitment service | The chosen time has already passed. | Choose another option. |
| SLOT_TAKEN | 409 | Recruitment service | The chosen time is no longer available. | Choose another option. |
| ALREADY_COMPLETED | 409 | Recruitment service | A completed interview was rescheduled or cancelled. | No retry. |
| INTERVIEW_CANCELLED | 409 | Recruitment service | A scorecard was submitted for a cancelled interview. | No retry. |
| SCORECARD_LOCKED | 409 | Recruitment service | The hiring decision is final, so the scorecard can no longer be edited. | No retry. |
| SCORECARD_NOT_ASSIGNED | 403 | Recruitment service | Someone other than the assigned interviewer submitted the scorecard. | The assigned interviewer must submit it. |
| SCORECARD_REQUIRED | 409 | Recruitment service | A candidate was moved to Offer (or to Hired with no offer) before any interview scorecard was completed. | Record the interview feedback first. |
Recruitment: candidates, requisitions and careers site
Requisition budget approval and candidate stage rules.
| Code | Status | Sent by | When | What to do |
|---|---|---|---|---|
| CANDIDATE_ALREADY_EXISTS | 409 | Recruitment service | A candidate with that email already exists for the job posting. | Use the existing candidate. |
| JOB_NOT_FOUND | 404 | Recruitment service | The role chosen for a referral or application no longer exists. | Pick another role. |
| STAGE_REQUIRES_HR | 403 | Recruitment service | A stage move into or out of a privileged stage was made without recruitment-management rights. | Ask someone with those rights. |
| SMTP_OFF | 409 | Recruitment service | A candidate message or rejection email could not be sent because outgoing email is not configured. Nothing was recorded as sent. | Configure email in Security Settings, then resend. |
| REQUISITION_NOT_BUDGET_APPROVED | 409 | Recruitment service | A requisition was opened or published before Finance approved the headcount budget. | Get the budget approved first. |
| COMP_CHANGE_NEEDS_REAPPROVAL | 409 | Recruitment service | The pay was changed on a live requisition, which sends it back for budget approval. | Set it to Draft or on hold, save, and reopen once approved. |
| FINANCE_SELF_APPROVAL | 403 | Recruitment service | The requisition creator tried to approve its budget. Not returned to a holder of the administrator role. | Another Finance approver must decide. |
| ALREADY_APPROVED | 409 | Recruitment service | The budget is already approved. | No retry. |
| ALREADY_REJECTED | 409 | Recruitment service | The budget is already refused. | No retry. |
| NOT_REJECTED | 409 | Recruitment service | A budget was resubmitted but it is not in the refused state. | Reload the requisition. |
| PERSONA_CONFER_UNVERIFIED | 403 | Recruitment service | A role blueprint was assigned to a requisition and the caller could not be verified as allowed to grant its access. | Retry; if it persists, contact an administrator. |
| ROLE_ESCALATION_BLOCKED | 403 | Recruitment service | The role blueprint confers access the caller is not permitted to grant. | Choose another blueprint, or ask an administrator. |
| ALERTS_OFF | 404 | Recruitment service | A job-alert sign-up arrived while job alerts are switched off. | Hide the sign-up form. |
| CONSENT_REQUIRED | 400 | Recruitment service | A job-alert sign-up did not include consent to receive the emails. | Collect consent and resend. |
E-signature
Returned to the person signing, on the public signing link. The 500 rows are the only server faults that name themselves.
| Code | Status | Sent by | When | What to do |
|---|---|---|---|---|
| ACCESS_DENIED | 400 | Signature service | The email or access code was wrong. The message gives the attempts left. | Re-enter; the link locks when attempts run out. |
| ACCESS_REQUIRED | 403 | Signature service | Signing was attempted before the access code was verified. | Verify the access code first. |
| CONSENT_REQUIRED | 400 | Signature service | Consent to electronic signing was not given. | Collect consent and resend. |
| SIGNATURE_REQUIRED | 400 | Signature service | The document needs a drawn or typed signature and none was sent. | Send the signature. |
| ALREADY_SIGNED | 410 | Signature service | The document was already signed; the link is no longer active. | No retry. |
| DECLINED | 410 | Signature service | The document was declined. | No retry. |
| WITHDRAWN | 410 | Signature service | The request was withdrawn while signing was being completed. Nothing was signed. | No retry. Contact the sender. |
| EXPIRED | 410 | Signature service | The signing link has expired. | The sender must issue a new link. |
| NOT_DECLINABLE | 409 | Signature service | The document is being signed or is already completed, so it cannot be declined. | No retry. |
| AUDIT_WRITE_FAILED | 500 | Signature service | The signing audit trail could not be written, so signing was aborted. | Retry; if it persists, an administrator should check the logs. |
| DOCUMENT_UNREADABLE | 500 | Signature service | The stored document could not be read. | An administrator should check the logs. |
| SIGN_INTERNAL_ERROR | 500 | Signature service | Signing failed for an internal reason that is deliberately not described to the signer. | Retry; if it persists, an administrator should check the logs. |
Compliance controls
Control status changes go through a review flow; these codes say which step was skipped.
| Code | Status | Sent by | When | What to do |
|---|---|---|---|---|
| USE_SUBMIT_FOR_REVIEW | 409 | Compliance service | A control was set to in-review directly. | Call the submit-for-review action instead. |
| CONTROL_IN_REVIEW | 409 | Compliance service | The control is in review and was changed before a decision. | Approve it or send it back first. |
| CONTROL_CHANGED | 409 | Compliance service | The control changed since it was loaded. | Reload and repeat. |
| AUTO_FAIL_NEEDS_EVIDENCE | 409 | Compliance service | A control whose automated evidence is failing was submitted or attested. | Fix the cause and let evidence re-collect. |
| DIGEST_RETIRED | 410 | Compliance service | The retired compliance digest endpoints were called. The body carries a "replacement" pointer. | Use scheduled reports. |
Security Lab
A scan of a remote target is checked against the scopes you have verified. Risk acceptance goes through an exception register with an expiry and an approver.
| Code | Status | Sent by | When | What to do |
|---|---|---|---|---|
| PROVIDER_NOT_CONFIGURED | 400 | Security Lab service | A cloud resource view was requested for a provider with no credentials. | Connect the provider, then retry. |
| PROVIDER_NOT_FOUND | 404 | Security Lab service | No provider of that type exists for the id. | Check the provider id. |
| RETEST_NOT_SUPPORTED | 400 | Security Lab service | The finding was not produced by a probe that can be re-run. The body carries "kind". | Re-check it the way the message describes. |
| RETEST_NEEDS_AUTH | 400 | Security Lab service | The finding came from an authenticated scan and the re-test sent no target credential. | Resend with targetAuth. |
| NOT_AUTHORIZED_TARGET | 403 | Security Lab service | The target host is not in an enabled scope whose ownership is verified, and the request carried no attestation. | Add the host to a scope and verify ownership, or attest that you are authorized to test it (safe checks only). |
| ATTESTATION_SAFE_ONLY | 403 | Security Lab service | A single probe more intensive than a passive or safe check was requested on an attestation alone, with no verified scope for the host. | Add the host to a scope and verify ownership, then repeat. |
| SCOPE_PROFILE_EXCEEDED | 403 | Security Lab service | The request is more intensive than the maximum profile the scope allows. | Raise the maximum profile on the scope, or request a less intensive scan. |
| JUSTIFICATION_REQUIRED | 400 | Security Lab service | A risk acceptance had no justification. | Send a justification. |
| EXPIRY_REQUIRED | 400 | Security Lab service | A risk acceptance had no expiry date, or one in the past. | Send a future acceptedUntil date. |
| EXCEPTION_EXISTS | 409 | Security Lab service | The finding or issue already has an exception. | Revoke the existing one first. |
| EXCEPTION_PENDING | 409 | Security Lab service | A risk acceptance is already waiting for a second approver. | Approve or revoke the pending one. |
| SOD_SELF_APPROVAL | 403 | Security Lab service | The requester tried to approve their own Critical or High risk acceptance. | A different person must approve. |
| SUBJECT_NOT_OPEN | 409 | Security Lab service | The finding or issue is no longer open, so there is no risk to accept. | Revoke the request. |
People and access
User lifecycle, role and directory sync refusals.
| Code | Status | Sent by | When | What to do |
|---|---|---|---|---|
| SUPPORT_ACCOUNT_MANAGED | 409 | User management service | A lifecycle change was attempted on the support-access account, which is controlled through support access. | Change it through support access instead. |
| PERSONA_NOT_FOUND | 404 | User management service | The role blueprint no longer exists. | Reload the list. |
| active_mover_run_exists | 409 | User management service | A role-change run is already open for this person. | Finish or cancel the open run first. |
| blast_radius_exceededin error | 409 | Integration service | A bulk directory sync would change a larger share of the directory than the configured safety limit. The body carries pct, cap, count and total. | Send fewer accounts, or repeat with "override": true. |
| NO_VENDOR_PRICE_FEED | 409 | User management service | A SaaS price sync could not sync anything; the message says why. | Follow the message. |