> ## Documentation Index
> Fetch the complete documentation index at: https://docs.corepillar.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors

> Every error code the API returns, with its HTTP status, what it means and what to do about it.

Errors use the error envelope:

```json theme={null}
{
  "error": {
    "code": "FORBIDDEN",
    "message": "Insufficient permissions.",
    "details": {}
  }
}
```

Branch on `code` and the HTTP status. The `message` is written for people and can change. `details` is always an object, usually empty; when it carries data, it's described below.

## Standard error codes

These come from the shared API error type and appear across the AgentHub endpoints.

| Code | HTTP status | Meaning | What to do |
| - | - | - | - |
| `UNAUTHORIZED` | 401 | No valid credentials. On ingestion: the tracing key is missing (`Tracing key required.`), malformed (`Invalid tracing key format.`) or unknown or revoked (`Invalid or revoked tracing key.`). On app endpoints: no signed-in session (`Authentication required.`). | Send a valid key or sign in again. Don't retry unchanged. |
| `FORBIDDEN` | 403 | You're signed in but not allowed. Either you're not a member of the organization (`You do not have access to this organization.`), your role lacks the permission (`Insufficient permissions.`), or the action is never allowed, such as editing or deleting a built-in default evaluator. | Check [the permission the endpoint needs](/api-reference/authentication#required-permission-per-endpoint), or ask an Owner or Admin. |
| `NOT_FOUND` | 404 | The trace, evaluator, run or scenario doesn't exist in this project or organization. | Check the id. Trace ids in a path must be URL-encoded. |
| `ORG_NOT_FOUND` | 404 | No organization with that slug is visible to you. | Check the slug and your membership. |
| `PROJECT_NOT_FOUND` | 404 | The project doesn't exist or isn't in an organization you belong to. Returned instead of `403` so other organizations' projects aren't revealed. | Check the project id and your membership. |
| `VALIDATION_ERROR` | 400 | The request body or a parameter is invalid. `message` names the first problem. | Fix the request. See [Validation details](#validation-details). |
| `VALIDATION_ERROR` | 413 | The upload is too large (synthetic data sources over 4 MB). | Send a smaller file. |
| `VALIDATION_ERROR` | 415 | Wrong `Content-Type`. The synthetic-data endpoints require `application/json`; the OTLP endpoints require `application/x-protobuf` or `application/json`. | Set the right header. |
| `VALIDATION_ERROR` | 422 | The request was well formed but its content can't be used: too little readable text in a synthetic-data source, an unsupported or unreadable document, or a URL that points at a blocked address. `details` may carry `hint` or `target`. | Use a different source. |
| `CONFLICT` | 409 | The user you're inviting is already a member (`User is already a member.`). | Nothing to do, or change their role instead. |
| `PLATFORM_ACCESS_REQUIRED` | 409 | You tried to invite an email address that hasn't been approved for platform access yet. | Approve the address under **Settings → Platform access** first. See [Platform access](/agenthub/settings/platform-access). |
| `RATE_LIMITED` | 429 | Too many requests to `POST /auth/sso-discovery` from your IP address (limit 30 per minute). | Wait a minute and retry. |
| `INTERNAL_ERROR` | 500 | Something failed on the server. The generic message is `An unexpected error occurred.` | Retry with backoff. If it keeps happening, contact your AgentHub administrator. |
| `INTERNAL_ERROR` | 502 | A model call that the endpoint depends on failed, for example scenario drafting or blueprint synthesis on the synthetic-data endpoints. | Retry. |
| `INTERNAL_ERROR` | 503 | A feature isn't configured on this deployment, for example `Scenario preview is not configured on this deployment.` | Contact your administrator. |

`MEMBER_NOT_FOUND` is defined in the error type but no endpoint currently returns it.

### Errors that surface as INTERNAL\_ERROR

Some failures that are really your input still come back as `500 INTERNAL_ERROR` with the generic message, because the underlying check runs in the database rather than in the API layer. Known cases:

| Endpoint | Cause |
| - | - |
| Most `POST` / `PATCH` / `PUT` app endpoints | The body isn't valid JSON. (The ingest endpoint returns `400` instead, and the synthetic-data, Cost Calculator streaming and recommendation endpoints also validate JSON properly.) |
| `PATCH /orgs/{orgId}/members/{userId}` | Trying to make someone else an Owner, or the member doesn't exist. |
| `DELETE /projects/{projectId}/tracing-keys/{keyId}` | The key doesn't exist or is already revoked. |
| `POST /orgs/{orgId}/evaluator-collections` | One of `evaluator_ids` doesn't exist or isn't visible to your organization. |
| `POST /projects/{projectId}/traces/{traceId}/evaluate` | The collection has LLM-judge evaluators but no `model_config_id` was sent, or the judge model wasn't found. |

## Validation details

`VALIDATION_ERROR` responses carry details in two shapes.

**Trace ingestion** returns the full list of problems, grouped by top-level field:

```json theme={null}
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid trace payload.",
    "details": {
      "issues": {
        "formErrors": [],
        "fieldErrors": {
          "trace_id": ["String must contain at least 1 character(s)"],
          "spans": ["Invalid datetime", "Required"]
        }
      }
    }
  }
}
```

Problems inside spans are reported under `spans` without the span index.

**Cost Calculator recommendations** and **evaluation explanations** return up to five raw issues with their paths:

```json theme={null}
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Array must contain at least 2 element(s)",
    "details": {
      "issues": [
        { "code": "too_small", "path": ["candidates"], "message": "Array must contain at least 2 element(s)" }
      ]
    }
  }
}
```

All other endpoints put only the first problem in `message` and leave `details` empty.

## OpenTelemetry endpoint errors

`POST /traces` (OTLP), `POST /metrics` and `POST /logs` use the error envelope only for failures that stop the whole request:

| Status | Code | Cause |
| - | - | - |
| 401 | `UNAUTHORIZED` | Tracing key missing, malformed or revoked. |
| 400 | `VALIDATION_ERROR` | `Unsupported Content-Encoding`, `OTLP payload is too large.` (over 32 MiB decompressed), or `Could not decode the protobuf OTLP payload` / `...json OTLP payload`. |
| 415 | `VALIDATION_ERROR` | `Content-Type must be application/x-protobuf or application/json.` |

Individual spans that can't be stored don't fail the request. They're reported in the OTLP response's `partialSuccess.rejectedSpans` with an `errorMessage`, and the request still returns `200`. See [OpenTelemetry (OTLP)](/agenthub/developers/opentelemetry#response).

## Chat and encryption-key endpoint errors

The ModelHub chat endpoints and the encryption-key endpoint use their own codes, in the shape `{ "error": { "code", "message" } }` without `details`.

| Code | HTTP status | Endpoint | Meaning |
| - | - | - | - |
| `UNAUTHENTICATED` | 401 | All chat endpoints, `/e2e/keys` | Not signed in (`Sign in to continue.`). |
| `INVALID_BODY` | 400 | `/chat/stream`, `/chat/scan`, `/chat/attachments`, `/e2e/keys` | The body didn't match the schema, or no file was attached in the `file` field. |
| `INVALID_QUERY` | 400 | `/chat/conversations`, `/e2e/keys` | Missing `org` or `project` query parameter. |
| `ORG_NOT_FOUND` | 404 | `/chat/stream`, `/e2e/keys` | The organization slug isn't visible to you. |
| `PROJECT_NOT_FOUND` | 404 | `/chat/stream`, `/chat/conversations` | The project slug isn't visible to you. |
| `NO_MODELS` | 409 | `/chat/stream` | `No models are configured for this project yet. Ask an admin to add one.` |
| `TOO_LARGE` | 413 | `/chat/attachments` | The file is over 10 MB. |
| `UNSUPPORTED_TYPE` | 422 | `/chat/attachments` | Not one of `.txt`, `.md`, `.markdown`, `.csv`, `.tsv`, `.json`, `.log`, `.pdf`, `.docx`. |
| `EMPTY` | 422 | `/chat/attachments` | The file has no text, for example a scanned PDF. |
| `ENCRYPTED` | 422 | `/chat/attachments` | The PDF is password-protected. |
| `UNREADABLE` | 422 | `/chat/attachments` | The file is damaged, binary, or not a valid PDF or Word document. |
| `ENROLL_FAILED` | 400 | `/e2e/keys` | The key couldn't be enrolled. |

### Errors inside a stream

Once a streaming response has started (`200`), failures arrive as an event in the stream rather than as an HTTP error:

* `POST /chat/stream` sends `data: {"type":"error","message":"..."}`. One expected case is a message that contains a credential or government identifier: the server sends a `pii` event and then an `error` event, and the client must resend with `overridePiiBlock: true` to continue.
* The Cost Calculator `.../stream` endpoints send `{"type":"error","message":"..."}` as an NDJSON line.

Authentication and validation failures on streaming endpoints happen before the stream starts and use the normal error responses above.


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