> ## Documentation Index
> Fetch the complete documentation index at: https://developer-staging.secfix.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors

> The error format and every error code.

Errors are returned as JSON. Handle them by the `code` field: codes don't change. `detail` is a
readable message that can change.

## Error format

```json theme={null}
{
  "type": "https://api.secfix.com/problems/not_found",
  "title": "Not Found",
  "status": 404,
  "detail": "No asset found for the given id.",
  "code": "not_found",
  "requestId": "req_01HZY8Q3M4N5P6R7S8T9V0W1X2"
}
```

| Field | Description |
| - | - |
| `code` | Stable error code. See [Error codes](#error-codes). |
| `status` | HTTP status code. |
| `title`, `detail` | Short summary and explanation. |
| `requestId` | The id of your request. Include it when you contact support. |

Every error also has `type`, a URI that names the error code. Some errors also include `instance`,
the path of the request.

## Request ids

To use your own request id, send an `X-Request-Id` header of 1–64 letters, digits, `-`, or `_`. The
API returns it in the `X-Request-Id` response header and as `requestId`. If you don't send one, or
it isn't valid, the API generates one.

A few errors, such as a request to an unknown path, may not include a `requestId` or return your
`X-Request-Id`.

## Error codes

| HTTP | `code` | Meaning |
| - | - | - |
| 400 | `validation_failed` | A parameter, header, or body field is invalid or missing, such as an `id` in the path that isn't a UUID. |
| 400 | `malformed_request` | The request body isn't valid JSON, or a body field has the wrong type. |
| 400 | `unsupported_grant_type` | `grant_type` on `POST /oauth/token` isn't `client_credentials`. |
| 401 | `unauthorized` | The access token is missing, invalid, or expired. |
| 401 | `token_superseded` | The token no longer works: a newer token replaced it, the API key's secret was rotated, a scope was removed from the key, or the key was deleted. Get a new token. |
| 401 | `invalid_client` | The `client_id` or `client_secret` is wrong. |
| 403 | `scope_required` | Your API key doesn't have access to this endpoint. See [Scopes](https://developer-staging.secfix.com/scopes.md). |
| 403 | `resource_not_writable` | The API can't change this resource. Only `CUSTOM` and `INFORMATION` assets can be created, updated, or deleted. Computers, cloud resources, and employees are read-only. A create that matches a hidden asset by `externalSource` and `externalAssetId` also returns it. |
| 403 | `forbidden` | The request was blocked. |
| 404 | `not_found` | The resource or path doesn't exist. |
| 405 | `method_not_allowed` | The path doesn't support this HTTP method. The `Allow` header lists the methods it supports. |
| 406 | `not_acceptable` | The `Accept` header doesn't allow `application/json`. |
| 409 | `idempotency_conflict` | The [`Idempotency-Key`](https://developer-staging.secfix.com/idempotency) was already used with a different body. |
| 409 | `idempotency_in_progress` | A request with the same [`Idempotency-Key`](https://developer-staging.secfix.com/idempotency) is still running. Wait the number of seconds in `Retry-After`, then retry with the same key. |
| 409 | `write_conflict` | Another write to the same asset was in progress, or another request created an asset with the same `externalSource` and `externalAssetId` at the same moment. Retry after the `Retry-After` header. |
| 413 | `payload_too_large` | The request body is too large. |
| 415 | `unsupported_media_type` | Send request bodies as `application/json`, or as `application/x-www-form-urlencoded` to `POST /oauth/token`. |
| 4xx | `request_rejected` | The request was rejected. Check it, then retry. |
| 429 | `rate_limited` | Too many requests. See [Rate limits](https://developer-staging.secfix.com/rate-limits.md). |
| 500, 502, 504 | `internal_error` | Something went wrong on our side. Wait a few minutes before you retry, because a request can keep running after your client gives up. Nothing may be stored under your [`Idempotency-Key`](https://developer-staging.secfix.com/idempotency), so a retry can run the request again. Before you retry a create, check whether the asset exists. |

## Errors in batch requests

Batch endpoints return `200` even when some records fail. Each failed record has its own `code` in
`results`:

| `code` | Meaning |
| - | - |
| `validation_failed` | A field in the record is invalid. `field` names it. |
| `resource_not_writable` | The asset isn't a `CUSTOM` or `INFORMATION` asset, or a create matched a hidden asset. |
| `not_editable` | Batch update only. None of the fields sent for that asset can be bulk-edited in its category, so nothing was saved. `skippedFields` lists them. |
| `not_found` | No asset has this `id`. |
| `write_conflict` | Another write to the asset was in progress. There is no `Retry-After` on a record: wait a second or two, then resend the record with a new `Idempotency-Key`. |
| `internal_error` | Something went wrong on our side. |

A `4xx` status on a batch means the API rejected the whole request and wrote nothing. Examples: an
empty `records` list, a repeated `id`, or an `id` that isn't a UUID (`malformed_request`).

A `5xx` or a timeout on a batch may have saved some records, because each record is saved on its own.
Nothing may be stored under your `Idempotency-Key`, so a retry with the same key runs every record
again. Before you resend a batch create, list your assets and send only the records that don't exist
yet, with a **new** key. If every record has `externalSource` and `externalAssetId`, you can resend the
whole batch instead: records that already exist are updated, not created again. See
[When a batch fails or times out](https://developer-staging.secfix.com/guides/inventory.md#when-a-batch-fails-or-times-out).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.