# Errors

> RFC 9457 application/problem+json with a machine-readable code and a hint.

Every non-2xx response has the content type `application/problem+json` ([RFC 9457](https://www.rfc-editor.org/rfc/rfc9457)) and this shape:

```json
{
  "type": "https://developers.gocubic.io/errors/invalid-api-key",
  "title": "Invalid API key",
  "status": 401,
  "code": "invalid_api_key",
  "detail": "The key in the Authorization header is not recognised or was revoked.",
  "hint": "Send 'Authorization: Bearer <key>'. Create a key at https://app.gocubic.io/settings/api-keys."
}
```

| Field | Meaning |
|---|---|
| `type` | URI of this error's section on this page. |
| `title` | Short summary. |
| `status` | The HTTP status code, repeated. |
| `code` | Stable, machine-readable. **Branch on this.** |
| `detail` | What went wrong with this request. |
| `hint` | How to fix the request. |
| `parameter` | The offending query parameter. Only on `invalid_parameter`. |

## Error codes

| `code` | HTTP status | Cause | Fix |
|---|---|---|---|
| [`missing_api_key`](#missing-api-key) | 401 | No `Authorization` header, or it is not in the `Bearer <key>` form. | Send `Authorization: Bearer $CUBIC_API_KEY`. Check the environment variable is set in the process that makes the request. |
| [`invalid_api_key`](#invalid-api-key) | 401 | The key is mistyped, truncated, or was revoked. | Do not retry with the same key. Ask the account owner to create a new key at https://app.gocubic.io/settings/api-keys. |
| [`shipment_not_found`](#shipment-not-found) | 404 | No shipment has that reference on the account the key belongs to. Shipments of other accounts return the same error. | Check the reference. To find a shipment by any other identifier use `GET /v1/shipments?search=`. |
| [`invalid_parameter`](#invalid-parameter) | 400 | A query parameter has a value that is out of range, malformed, or not an allowed enum value. | Read `parameter` to see which one, and `hint` for the allowed values. Correct the request; do not retry unchanged. |
| [`invalid_cursor`](#invalid-cursor) | 400 | The `cursor` value was altered, or is reused with different filters than the request that produced it. | Restart from the first page without `cursor`. Never build or modify cursors. |
| [`rate_limited`](#rate-limited) | 429 | More than 60 requests in one minute on this key. | Wait `Retry-After` seconds, then retry the same request. |
| [`internal_error`](#internal-error) | 500 | A fault on the Cubic side. | Retry with exponential backoff. If it persists, contact Cubic. |

## What to retry

| Status | Retry? |
|---|---|
| 400, 401, 404 | No. Fix the request using `hint`. |
| 429 | Yes, after `Retry-After` seconds. See [Rate limits](https://developers.gocubic.io/rate-limits.md). |
| 500 | Yes, with exponential backoff. |

## Examples

### `missing_api_key`

```json
{
  "type": "https://developers.gocubic.io/errors/missing-api-key",
  "title": "Missing API key",
  "status": 401,
  "code": "missing_api_key",
  "detail": "The request has no Authorization header.",
  "hint": "Send 'Authorization: Bearer <key>'. Create a key at https://app.gocubic.io/settings/api-keys."
}
```

### `invalid_api_key`

```json
{
  "type": "https://developers.gocubic.io/errors/invalid-api-key",
  "title": "Invalid API key",
  "status": 401,
  "code": "invalid_api_key",
  "detail": "The key in the Authorization header is not recognised or was revoked.",
  "hint": "Send 'Authorization: Bearer <key>'. Create a key at https://app.gocubic.io/settings/api-keys."
}
```

### `shipment_not_found`

```json
{
  "type": "https://developers.gocubic.io/errors/shipment-not-found",
  "title": "Shipment not found",
  "status": 404,
  "code": "shipment_not_found",
  "detail": "No shipment with reference 'QB99999' exists on this account.",
  "hint": "Check the reference (for example 'QB10293'). To look a shipment up by PO number, container, master bill or FBA ID, call GET /v1/shipments?search=<value>."
}
```

### `invalid_parameter`

```json
{
  "type": "https://developers.gocubic.io/errors/invalid-parameter",
  "title": "Invalid parameter",
  "status": 400,
  "code": "invalid_parameter",
  "detail": "'Shipped' is not a valid value for 'status'.",
  "hint": "Use one of: Active, Delivered, Cancelled. Repeat the parameter to filter by several statuses.",
  "parameter": "status"
}
```

### `invalid_cursor`

```json
{
  "type": "https://developers.gocubic.io/errors/invalid-cursor",
  "title": "Invalid cursor",
  "status": 400,
  "code": "invalid_cursor",
  "detail": "The cursor is malformed or was issued for a different set of filters.",
  "hint": "Restart pagination: repeat the request without 'cursor', then follow 'nextCursor' from each response."
}
```

### `rate_limited`

```json
{
  "type": "https://developers.gocubic.io/errors/rate-limited",
  "title": "Rate limit exceeded",
  "status": 429,
  "code": "rate_limited",
  "detail": "This key has made more than 60 requests in the last minute.",
  "hint": "Wait the number of seconds in the 'Retry-After' header, then retry the same request."
}
```

### `internal_error`

```json
{
  "type": "https://developers.gocubic.io/errors/internal-error",
  "title": "Internal error",
  "status": 500,
  "code": "internal_error",
  "detail": "An unexpected error occurred while handling the request.",
  "hint": "Retry with exponential backoff. The request itself is not the problem."
}
```
