Skip to Content
Welcome to the Novantra documentation.

Errors

Errors return a consistent JSON envelope and a matching HTTP status code. Branch on the status code and the structured error field, not on the human-readable message.

Error envelope

Every error response body has this shape:

{ "error": "validation", "message": "Request failed validation.", "issues": [ { "path": ["reason"], "message": "Required" } ], "requestId": "req_01HXY..." }
FieldAlways presentNotes
erroryesStable machine-readable identifier. Branch on this.
messageyesHuman-readable summary. Do not parse for logic.
issuesonly for validation errorsField-level details, with path (JSON pointer-like array) and message.
requestIdyesUnique request ID. Include in support tickets.

The same requestId is also returned in the X-Request-Id response header on every response (success or error).

Status codes

Statuserror identifierMeaning
400validationThe request body or query failed validation. Inspect issues to see which fields failed.
401unauthenticatedNo bearer token, or the token is invalid or expired. Re-issue a token.
403forbiddenAuthenticated but the token’s scopes don’t permit this action, or the workspace forbids it.
404not_foundThe resource does not exist or is not visible to this token.
409conflictThe action conflicts with the current state (e.g., creating a record with a controlKey that already exists).
410goneThe endpoint has been sunset (see Versioning).
422unprocessableThe request shape was correct but the action is semantically invalid in the current context.
429rate_limitedYou exceeded the rate limit. Honor the Retry-After header. See Rate limits.
5xxinternalServer error. Retry safely after a short delay. Include the requestId if you escalate.

Idempotency keys

Most write endpoints accept an Idempotency-Key header. Use one whenever your integration can’t guarantee at-most-once delivery (which is most real-world scenarios: network retries, queue redeliveries, scheduled job overlaps).

POST /api/v1/governance/findings Idempotency-Key: scanner-batch-2026-05-21-item-3947 Content-Type: application/json { ... }

Semantics:

  • First call: processed normally. The system stores the response keyed by (token, idempotency-key).
  • Repeated call with the same key: returns the original response (same status code, same body, same headers including requestId). The action is not re-executed.
  • Repeated call with the same key but a different body: rejected with 409 conflict and error: "idempotency_mismatch". This prevents accidentally repurposing a key.
  • Retention: stored responses are retained for 24 hours. After that, the key is forgotten and a repeated request will be processed as new.

Idempotency keys must be unique strings between 8 and 128 characters. Use a value that uniquely identifies the intent of the call (a row ID from your source system, a scan ID, etc.), not a random UUID generated per attempt.

Idempotency keys are scoped to the service-account token that made the original call. The same key from a different token does not match.

Retry guidance

When and how to retry:

StatusRetry?How
2xxn/asucceeded.
400, 403, 404, 409, 422No.These represent client-side problems that won’t fix themselves. Fix the request, then call again.
401Yes, once after refreshing the token.If the new call also returns 401, treat as authentication misconfiguration.
410No.The endpoint is gone. Migrate to the replacement (see Link header).
429Yes, after honoring Retry-After.Use exponential backoff if you hit it repeatedly.
500, 502, 503, 504Yes, with exponential backoff.Pair with an idempotency key on writes to avoid double-processing. Cap the retries (5 is a sensible default).

Common retry pattern:

attempt = 1 while attempt <= 5: call_api(idempotency_key=...) if success or non-retryable: return sleep(min(2^attempt * 100ms + jitter, 30s)) attempt += 1

Validation error details

Validation errors (400 / error: "validation") include a structured issues array:

{ "error": "validation", "message": "Request failed validation.", "issues": [ { "path": ["reason"], "message": "String must contain at least 10 character(s)" }, { "path": ["subjectResourceId"], "message": "Expected string, received null" } ], "requestId": "req_01HXY..." }

path is an array describing how to navigate into the request body to find the offending field. For top-level fields, it’s a single-element array. For nested fields, it’s the full traversal: ["pages", 2, "title"] means “the title of element index 2 of the pages array.”

Common error scenarios

”I’m getting 409 conflict on the same controlKey

You’re trying to create a control with a key that already exists in your workspace. Either pick a different key, or fetch the existing record by listing with a filter and update it instead.

”I’m getting 401 after a few hours of successful calls”

Your access token expired. Re-exchange the client credentials for a fresh token. Don’t request a new token per call; cache the token until shortly before its expires_in.

”I’m getting 403 on every call from one service account”

Either:

  • The token’s scopes don’t include the action you’re attempting. Check the response: it tells you which scope was needed.
  • The service account was disabled by a workspace admin.

”I’m getting 429 repeatedly even after waiting”

Your integration’s call volume exceeds the rate limit for your token. See Rate limits; contact your account team if you need a higher limit for a documented use case.

Including request IDs in support tickets

When something looks wrong, always include the requestId (from the response body or the X-Request-Id header) in your support ticket. With the request ID, Novantra support can find the exact request in internal logs and tell you what happened.

Next

Last updated on