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

# Error handling

> Interpret the common error envelope, classify failures, decide retry behavior, and collect actionable diagnostics.

Every public API error uses this envelope:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "The request could not be validated.",
    "requestId": "018f3d9a-7dfb-7a23-b4b4-9f7e4b19d4b4"
  }
}
```

Use the HTTP status for the broad failure class and `error.code` for precise handling.

## Decision flow

```mermaid theme={"theme":{"light":"github-light","dark":"github-dark"}}
flowchart TD
    A[API response is not successful] --> B{HTTP status}
    B -->|400 / 406 / 413 / 415 / 422| C[Correct request or data]
    B -->|401| D[Check API key and active status]
    B -->|403| E[Check tenant and API-key scope]
    B -->|404| F[Check ID, scope, and file availability]
    B -->|409| G[Re-read resource state]
    B -->|429| H[Honor Retry-After]
    B -->|500 / 502 / 503 / 504| I[Retry only when replay is safe]
```

## Error catalog

| Error code                               | Typical HTTP class | Meaning                                                           | Client action                                      |       Retry |
| ---------------------------------------- | -----------------: | ----------------------------------------------------------------- | -------------------------------------------------- | ----------: |
| `INVALID_API_KEY`                        |              `401` | Key is missing, invalid, deleted, or inactive                     | Replace or reactivate credential                   |          No |
| `INVALID_REQUEST_ID`                     |              `400` | Request ID is not UUID v4 or v7                                   | Generate a valid value                             |          No |
| `NOT_ACCEPTABLE`                         |              `406` | Requested response representation is unavailable                  | Correct `Accept`                                   |          No |
| `UNSUPPORTED_MEDIA_TYPE`                 |              `415` | Request media type is not accepted                                | Use documented content type                        |          No |
| `MISSING_ATTACHMENT`                     |      `400` / `422` | Multipart request has no required upload                          | Add the required `uploads` field                   |          No |
| `PAYLOAD_TOO_LARGE`                      |              `413` | Complete request exceeds 5 MiB                                    | Reduce JSON or multipart size                      |          No |
| `UNKNOWN_QUERY_PARAMETER`                |              `400` | Query parameter is not supported                                  | Remove unknown parameter                           |          No |
| `UNSUPPORTED_HEADER`                     |              `400` | Header is not accepted                                            | Remove or correct header                           |          No |
| `NOT_FOUND`                              |              `404` | Resource is absent or not visible in scope                        | Verify ID and tenant context                       |          No |
| `FILE_NOT_FOUND`                         |              `404` | Referenced file is unavailable                                    | Re-read metadata and availability                  |          No |
| `TENANT_CONTEXT_AMBIGUOUS`               |      `400` / `422` | One target tenant cannot be resolved                              | Send `X-Tenant-ID`                                 |          No |
| `EMPLOYEE_PLACEMENT_AMBIGUOUS`           |              `422` | Employee placement does not resolve one allowed division          | Send an allowed `divisionId`                       |          No |
| `TENANT_NOT_IN_SCOPE`                    |              `403` | Tenant is outside key scope                                       | Correct scope or tenant                            |          No |
| `INVALID_REFERENCE_ID`                   |      `400` / `422` | Reference ID has invalid format                                   | Use an ID returned by JobHandy                     |          No |
| `INVALID_REFERENCE`                      |      `404` / `422` | Referenced resource is missing or unavailable                     | Re-read reference and scope                        |          No |
| `VALIDATION_ERROR`                       |              `422` | Request violates schema or business validation                    | Correct payload                                    |          No |
| `INVALID_FILTER_SYNTAX`                  |      `400` / `422` | Filter cannot be parsed                                           | Correct quoting and expression                     |          No |
| `UNSUPPORTED_FILTER_FIELD`               |              `422` | Field is not filterable                                           | Use endpoint-supported field                       |          No |
| `UNSUPPORTED_FILTER_OPERATOR`            |              `422` | Operator is invalid for field                                     | Use supported operator                             |          No |
| `UNSUPPORTED_SORT_FIELD`                 |              `422` | Sort field is unavailable                                         | Use documented scalar field                        |          No |
| `UNSUPPORTED_FIELD`                      |              `422` | Field is not writable or selectable                               | Remove unsupported field                           |          No |
| `EMPLOYEE_BLOCKED`                       |      `409` / `422` | Employee state prevents operation                                 | Resolve employee status                            |          No |
| `EMPLOYEE_NOT_ACTIVATED`                 |              `422` | An incident references an employee whose activation is incomplete | Activate the employee before creating the incident |          No |
| `DIVISION_CYCLE`                         |      `409` / `422` | Parent update would create hierarchy cycle                        | Choose a valid parent                              |          No |
| `DIVISION_NAME_NOT_UNIQUE_ON_SAME_LEVEL` |              `409` | Sibling name already exists                                       | Use a unique sibling name                          |          No |
| `DUPLICATE_RESOURCE`                     |              `409` | Uniqueness rule is violated                                       | Locate and reconcile existing resource             |          No |
| `INVALID_STATE_TRANSITION`               |              `409` | Requested lifecycle transition is not allowed                     | Re-read state and stop blind retries               |          No |
| `ORDER_ALREADY_DECIDED`                  |              `409` | HR decision is already final                                      | Re-read and reconcile                              |          No |
| `RATE_LIMIT_EXCEEDED`                    |              `429` | API-key quota is exhausted                                        | Honor `Retry-After`                                |         Yes |
| `BAD_GATEWAY`                            |              `502` | Upstream dependency failed                                        | Retry safe reads/downloads only                    | Conditional |
| `SERVICE_UNAVAILABLE`                    |              `503` | Service or dependency unavailable                                 | Backoff; reconcile writes                          | Conditional |
| `GATEWAY_TIMEOUT`                        |              `504` | Dependency timed out                                              | Backoff; reconcile writes                          | Conditional |
| `INTERNAL_SERVER_ERROR`                  |              `500` | Unexpected server failure                                         | Log request ID and retry only if safe              | Conditional |

The exact status and errors available for an operation remain authoritative in that endpoint's OpenAPI response list.

## Diagnostic record

Store the following for every failed attempt:

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
UTC timestamp
HTTP method
path template, not a URL containing secrets
HTTP status
error.code
error.message
error.requestId / X-Request-ID
tenant context
attempt number
logical operation ID
```

Do not store the API key or unnecessary personal data.

<Card title="Troubleshooting runbook" icon="wrench" horizontal href="/operations/troubleshooting">
  Follow the operation-specific checks before opening a support request.
</Card>
