# Errors

> The error envelope and the codes you will meet, with how to resolve each.

Every error response uses the same envelope, so you can handle failures uniformly.

## The envelope

```json
{
  "error": {
    "code": "origin_not_allowed",
    "message": "Origin https://evil.example is not allowed for this form. Allowed: https://example.com",
    "docs_url": "https://lanes.sh/docs/forms/securing-your-endpoints"
  }
}
```

Branch on the stable `code`, not on the human-readable `message`. Messages are written to be **self-correcting**: where it helps, they include the value that failed and what was expected, so an agent can often fix the call from the message alone.

## Provisioning errors

| Code | Status | Fix |
| --- | --- | --- |
| `disposable_email` | 422 | Use a real, non-disposable recipient address. |
| `pending_claim_exists` | 429 | An unclaimed form for that email already exists. Claim or reuse it. |

## Submission errors

| Code | Status | Fix |
| --- | --- | --- |
| `form_not_found` | 404 | Check the `form_id` in the URL. |
| `unsupported_content_type` | 415 | Set a `Content-Type` (`application/json`, form-urlencoded, or multipart). |
| `files_not_supported` | 415 | Remove file parts. Uploads are not supported in v1. |
| `invalid_body` | 400 | Send a JSON object of field values, not an array or scalar. |
| `missing_required_fields` | 422 | The response lists the missing fields. Provide them. |
| `payload_too_large` | 413 | Keep the body under 64 KB. |
| `submission_rate_limited` | 429 | Back off. The limit is 10 per minute per IP. |
| `unclaimed_submission_cap` | 429 | The form hit 25 stored submissions. It must be [claimed](/docs/forms/claiming) to accept more. |

## Security errors

| Code | Status | Fix |
| --- | --- | --- |
| `origin_not_allowed` | 403 | Add the origin to the form's `allowed_origins`. |
| `preflight_origin_required` | 400 | The CORS preflight sent no `Origin`. |
| `api_key_required` | 401 | The form is in `api_key` mode. Send `Authorization: Bearer lfk_...`. |
| `invalid_api_key` | 401 | The key is unknown or revoked. Create a new one. |
| `api_key_limit_reached` | 429 | A workspace allows 10 active keys. Revoke an unused one. |
| `api_key_not_found` | 404 | The key id does not belong to this workspace. |

## Delivery errors

| Code | Status | Fix |
| --- | --- | --- |
| `action_not_available` | 422 | Webhook and custom (non-Lanes) storage are not live yet. Use email plus Lanes storage. |

State-gate responses (`410`) are returned when a form is `frozen` or `deleted`; see [Provisioning](/docs/forms/provisioning#form-states).

Next: [API reference](/docs/forms/api-reference).
