# Music API errors

> Part of the MAP Audio Music API docs. Index of every page: https://map.audio/developers/music-api/llms.txt. OpenAPI document: https://map.audio/developers/music-api/openapi.json.

Every error the Music API answers with has the same JSON shape and a stable code. This page lists each code, when it happens and what to do next.

The body is `{"error":{"type","code","message","param","details","retryable","requestId","jobId","docUrl"}}`. `code` names an entry below, and `docUrl` links to it. `param` names the field at fault in the body's own notation, such as `items[0].name`. `retryable` says whether the same request can succeed later: honour `Retry-After` when it is sent, and change the request when it is not retryable. Quote `requestId`, which is also the `Request-Id` header, when you report a problem to support@map.audio. New codes can appear within a version; handle one you do not know by its `type` and `retryable`.

| Code | Status | Type | Retryable |
| --- | --- | --- | --- |
| [`invalid_request`](#invalid_request) | 400 | invalid_request | no |
| [`not_invited`](#not_invited) | 403 | entitlement | no |
| [`authentication_failed`](#authentication_failed) | 401 | authentication | no |
| [`insufficient_scope`](#insufficient_scope) | 403 | entitlement | no |
| [`auth_unavailable`](#auth_unavailable) | 503 | unavailable | yes |
| [`account_suspended`](#account_suspended) | 403 | entitlement | no |
| [`customer_erased`](#customer_erased) | 409 | conflict | no |
| [`already_has_access`](#already_has_access) | 409 | conflict | no |
| [`access_request_needs_sign_in`](#access_request_needs_sign_in) | 403 | entitlement | no |
| [`rate_limited`](#rate_limited) | 429 | rate_limit | yes |
| [`route_not_found`](#route_not_found) | 404 | not_found | no |
| [`method_not_allowed`](#method_not_allowed) | 405 | invalid_request | no |
| [`unsupported_media_type`](#unsupported_media_type) | 415 | invalid_request | no |
| [`version_unsupported`](#version_unsupported) | 400 | invalid_request | no |
| [`payload_too_large`](#payload_too_large) | 413 | too_large | no |
| [`not_found`](#not_found) | 404 | not_found | no |
| [`idempotency_key_unsupported`](#idempotency_key_unsupported) | 400 | invalid_request | no |
| [`idempotency_key_reused`](#idempotency_key_reused) | 409 | conflict | no |
| [`idempotency_in_flight`](#idempotency_in_flight) | 409 | conflict | yes |
| [`oauth_required`](#oauth_required) | 403 | entitlement | no |
| [`terms_required`](#terms_required) | 403 | entitlement | no |
| [`terms_version_mismatch`](#terms_version_mismatch) | 400 | invalid_request | no |
| [`too_many_keys`](#too_many_keys) | 403 | entitlement | no |
| [`too_many_endpoints`](#too_many_endpoints) | 403 | entitlement | no |
| [`rotation_in_progress`](#rotation_in_progress) | 409 | conflict | no |
| [`endpoint_disabled`](#endpoint_disabled) | 409 | conflict | no |
| [`billing_unavailable`](#billing_unavailable) | 503 | unavailable | no |
| [`subscription_exists`](#subscription_exists) | 409 | conflict | no |
| [`billing_not_available`](#billing_not_available) | 409 | conflict | no |
| [`billing_rate_limited`](#billing_rate_limited) | 429 | rate_limit | yes |
| [`insufficient_credits`](#insufficient_credits) | 402 | entitlement | no |
| [`concurrency_limit`](#concurrency_limit) | 429 | rate_limit | yes |
| [`queue_unavailable`](#queue_unavailable) | 503 | unavailable | yes |
| [`internal_error`](#internal_error) | 500 | unavailable | yes |
| [`preset_not_found`](#preset_not_found) | 404 | not_found | no |
| [`preset_not_served`](#preset_not_served) | 400 | invalid_request | no |
| [`variation_not_found`](#variation_not_found) | 400 | invalid_request | no |
| [`quality_unavailable`](#quality_unavailable) | 400 | invalid_request | no |
| [`render_too_long`](#render_too_long) | 400 | invalid_request | no |
| [`file_not_ready`](#file_not_ready) | 409 | conflict | yes |
| [`file_expired`](#file_expired) | 410 | gone | no |
| [`download_link_invalid`](#download_link_invalid) | 403 | authentication | no |
| [`uploads_disabled`](#uploads_disabled) | 403 | entitlement | no |
| [`upload_closed`](#upload_closed) | 409 | conflict | no |
| [`upload_expired`](#upload_expired) | 410 | gone | no |
| [`upload_incomplete`](#upload_incomplete) | 409 | conflict | no |
| [`upload_processing`](#upload_processing) | 409 | conflict | yes |
| [`checksum_mismatch`](#checksum_mismatch) | 400 | invalid_request | no |
| [`dj_invalid_set`](#dj_invalid_set) | 400 | invalid_request | no |
| [`dj_offline_unsupported`](#dj_offline_unsupported) | 400 | invalid_request | no |
| [`dj_preset_missing`](#dj_preset_missing) | 400 | invalid_request | no |
| [`dj_unknown_transition_preset`](#dj_unknown_transition_preset) | 400 | invalid_request | no |
| [`invalid_envelope`](#invalid_envelope) | 400 | invalid_request | no |
| [`invalid_batch_line`](#invalid_batch_line) | 400 | invalid_request | no |
| [`unknown_op`](#unknown_op) | 400 | invalid_request | no |
| [`invalid_project`](#invalid_project) | 400 | invalid_request | no |
| [`unsupported_project`](#unsupported_project) | 415 | invalid_request | no |
| [`project_too_large`](#project_too_large) | 413 | too_large | no |
| [`pack_license_required`](#pack_license_required) | 403 | entitlement | no |
| [`license_required`](#license_required) | 503 | unavailable | yes |
| [`resource_exhausted`](#resource_exhausted) | 503 | unavailable | yes |
| [`engine_busy`](#engine_busy) | 503 | unavailable | yes |
| [`render_busy`](#render_busy) | 503 | unavailable | yes |
| [`engine_unavailable`](#engine_unavailable) | 503 | unavailable | yes |
| [`timeout`](#timeout) | 504 | engine | no |
| [`engine_failed`](#engine_failed) | 500 | engine | yes |
| [`encode_failed`](#encode_failed) | 500 | engine | no |
| [`no_candidate_passed`](#no_candidate_passed) | 422 | engine | no |

## invalid_request

Invalid request. Status 400, type `invalid_request`, not retryable.

When: A field, query parameter or header is missing, has the wrong type or is out of range. `param` names it, in the body's own notation (items[0].name).

Fix: Change the field `param` names as the message says, then send the request again.

```json
{
  "error": {
    "type": "invalid_request",
    "code": "invalid_request",
    "message": "Invalid request",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#invalid_request"
  }
}
```

## not_invited

No Music API access yet. Status 403, type `entitlement`, not retryable.

When: The map.audio account behind the access token has no Music API account. `details.customerId` names it, `details.emailConfirmed` says whether this sign-in proved its email address, `details.accessRequest` shows any request already sent and `details.requestAccessUrl` is where to ask.

Fix: Request access at https://map.audio/music (or POST /v1/access-requests with the same token). If `details.emailConfirmed` is false and MAP Audio invited your address, sign in again and confirm it with the emailed code. If an invite went to another address, sign in with that address.

```json
{
  "error": {
    "type": "entitlement",
    "code": "not_invited",
    "message": "No Music API access yet",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#not_invited"
  }
}
```

## authentication_failed

Authentication failed. Status 401, type `authentication`, not retryable.

When: The request has no `Authorization: Bearer` header, or its API key or map.audio access token is malformed, quoted, unknown, revoked or issued for another API. The `WWW-Authenticate` header points OAuth clients at the resource metadata.

Fix: Send `Authorization: Bearer` followed by an API key (sk_test_ or sk_live_ and 40 letters and digits) or a current map.audio access token, with nothing around it. The message says which part was wrong.

```json
{
  "error": {
    "type": "authentication",
    "code": "authentication_failed",
    "message": "Authentication failed",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#authentication_failed"
  }
}
```

## insufficient_scope

Token lacks the audio scope. Status 403, type `entitlement`, not retryable.

When: The map.audio access token was granted without the `audio` scope.

Fix: Sign in again and ask for the `audio` scope; GET /.well-known/oauth-protected-resource lists it.

```json
{
  "error": {
    "type": "entitlement",
    "code": "insufficient_scope",
    "message": "Token lacks the audio scope",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#insufficient_scope"
  }
}
```

## auth_unavailable

Sign-in check unavailable. Status 503, type `unavailable`, retryable.

When: The map.audio sign-in service could not check the access token just now. API keys do not depend on this check.

Fix: Retry in a few seconds with the same token; signing in again does not help.

```json
{
  "error": {
    "type": "unavailable",
    "code": "auth_unavailable",
    "message": "Sign-in check unavailable",
    "param": null,
    "retryable": true,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#auth_unavailable"
  }
}
```

## account_suspended

Account suspended. Status 403, type `entitlement`, not retryable.

When: The Music API account behind this API key or sign-in is suspended: MAP Audio suspended it, or the map.audio customer was erased.

Fix: Email support@map.audio and quote the response's Request-Id.

```json
{
  "error": {
    "type": "entitlement",
    "code": "account_suspended",
    "message": "Account suspended",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#account_suspended"
  }
}
```

## customer_erased

Customer erased. Status 409, type `conflict`, not retryable.

When: The map.audio customer behind this sign-in was erased, so the Music API cannot open an account or take an access request for them.

Fix: This cannot be undone. Email support@map.audio if you think it is a mistake.

```json
{
  "error": {
    "type": "conflict",
    "code": "customer_erased",
    "message": "Customer erased",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#customer_erased"
  }
}
```

## already_has_access

Already has access. Status 409, type `conflict`, not retryable.

When: POST /v1/access-requests was sent with the access token of a map.audio account that already has Music API access.

Fix: Nothing to request: call the API with the same token, or create API keys at https://map.audio/music.

```json
{
  "error": {
    "type": "conflict",
    "code": "already_has_access",
    "message": "Already has access",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#already_has_access"
  }
}
```

## access_request_needs_sign_in

Access requests need a sign-in. Status 403, type `entitlement`, not retryable.

When: POST /v1/access-requests was sent with an API key. A key always belongs to an account that has access, so a request needs the map.audio access token of the account that wants it.

Fix: Sign in at https://map.audio/music with the map.audio account that needs access and request it there, or send that account's access token.

```json
{
  "error": {
    "type": "entitlement",
    "code": "access_request_needs_sign_in",
    "message": "Access requests need a sign-in",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#access_request_needs_sign_in"
  }
}
```

## rate_limited

Rate limited. Status 429, type `rate_limit`, retryable.

When: More requests arrived within a minute than a limit allows. The message names the limit and what it counts: one API key, the map.audio sign-ins of one account, the access requests of one account, or one network address.

Fix: Wait the seconds in `Retry-After`, then send again. To follow a job, use `Prefer: wait`, the job's events stream or a webhook rather than polling.

```json
{
  "error": {
    "type": "rate_limit",
    "code": "rate_limited",
    "message": "Rate limited",
    "param": null,
    "retryable": true,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#rate_limited"
  }
}
```

## route_not_found

No such route. Status 404, type `not_found`, not retryable.

When: No route has this path, whatever the method. The message repeats the method and path, and suggests a route when one is a typo away. A trailing slash is ignored.

Fix: Check the path against the reference at https://map.audio/developers/music-api/reference or GET /v1/openapi.json.

```json
{
  "error": {
    "type": "not_found",
    "code": "route_not_found",
    "message": "No such route",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#route_not_found"
  }
}
```

## method_not_allowed

Method not allowed. Status 405, type `invalid_request`, not retryable.

When: The path exists, but not with this method. The `Allow` header lists the methods it takes; HEAD is answered wherever GET is.

Fix: Send one of the methods in `Allow`. The message names where a related list lives, such as GET /v1/jobs for the jobs a POST route starts.

```json
{
  "error": {
    "type": "invalid_request",
    "code": "method_not_allowed",
    "message": "Method not allowed",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#method_not_allowed"
  }
}
```

## unsupported_media_type

Unsupported media type. Status 415, type `invalid_request`, not retryable.

When: A route that takes a JSON body got one without `Content-Type: application/json`, with another media type, or compressed (`Content-Encoding`). `param` names the header and the message names what was sent.

Fix: Send the body uncompressed, as JSON, with `Content-Type: application/json`. Routes that take no body (cancel, rotate-secret, test, billing portal) need neither.

```json
{
  "error": {
    "type": "invalid_request",
    "code": "unsupported_media_type",
    "message": "Unsupported media type",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#unsupported_media_type"
  }
}
```

## version_unsupported

API version not served. Status 400, type `invalid_request`, not retryable.

When: The `Map-Version` request header names a version this API does not serve. Every response carries the version it answered with in `Map-Version`.

Fix: Send `Map-Version: 2026-11-01`, or leave the header out to get the current version.

```json
{
  "error": {
    "type": "invalid_request",
    "code": "version_unsupported",
    "message": "API version not served",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#version_unsupported"
  }
}
```

## payload_too_large

Body too large. Status 413, type `too_large`, not retryable.

When: The body is over the route's limit (256 KiB, or 2 MiB on the command routes), an upload declares more bytes than its kind allows, or one JSON field is over 1 MiB. `param` names the field when one is to blame.

Fix: Send less: shorter envelopes or chains, fewer items per request.

```json
{
  "error": {
    "type": "too_large",
    "code": "payload_too_large",
    "message": "Body too large",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#payload_too_large"
  }
}
```

## not_found

Not found. Status 404, type `not_found`, not retryable.

When: No job, file, plan, API key, webhook endpoint or provenance record with that id is visible to this account. `param` names the id (`id` for a path id). Another account's ids answer exactly as missing ones do.

Fix: Check the id against the list route the message names, such as GET /v1/jobs or GET /v1/files; job and plan ids also get their expected shape in the message.

```json
{
  "error": {
    "type": "not_found",
    "code": "not_found",
    "message": "Not found",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#not_found"
  }
}
```

## idempotency_key_unsupported

Idempotency-Key not taken here. Status 400, type `invalid_request`, not retryable.

When: An `Idempotency-Key` header was sent to a route that does not replay requests. Only routes that start a job take one: POST /v1/renders, the command routes and POST /v1/uploads/{id}/complete.

Fix: Leave the header out on this route. A route that creates something (a key, a webhook endpoint) creates another on a retry, so list first to see whether the first attempt landed.

```json
{
  "error": {
    "type": "invalid_request",
    "code": "idempotency_key_unsupported",
    "message": "Idempotency-Key not taken here",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#idempotency_key_unsupported"
  }
}
```

## idempotency_key_reused

Idempotency-Key reused. Status 409, type `conflict`, not retryable.

When: This `Idempotency-Key` was used in the last 24 hours with a different route or body.

Fix: Use a new key for a new request. To replay the first answer, send the first request again unchanged.

```json
{
  "error": {
    "type": "conflict",
    "code": "idempotency_key_reused",
    "message": "Idempotency-Key reused",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#idempotency_key_reused"
  }
}
```

## idempotency_in_flight

Same request in flight. Status 409, type `conflict`, retryable.

When: A request with this `Idempotency-Key` is still being accepted.

Fix: Retry the same request, with the same key, after a few seconds.

```json
{
  "error": {
    "type": "conflict",
    "code": "idempotency_in_flight",
    "message": "Same request in flight",
    "param": null,
    "retryable": true,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#idempotency_in_flight"
  }
}
```

## oauth_required

Needs the account owner's sign-in. Status 403, type `entitlement`, not retryable.

When: Creating or revoking API keys, buying a plan or render-minutes and opening the billing portal need the account owner signed in at https://map.audio/music. Webhook endpoints take an API key or that sign-in. This request used an API key or another app's sign-in.

Fix: Do it at https://map.audio/music, signed in as the account owner.

```json
{
  "error": {
    "type": "entitlement",
    "code": "oauth_required",
    "message": "Needs the account owner's sign-in",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#oauth_required"
  }
}
```

## terms_required

Terms not accepted. Status 403, type `entitlement`, not retryable.

When: The account has not accepted the current prototype terms, which every route that starts work needs. Creating an API key without `acceptTerms` on such an account answers this too.

Fix: Read and accept the terms at https://map.audio/music, or send POST /v1/account/terms with {"accept": "2026-11-01-prototype"}, or call the MCP tool accept_terms. GET /v1/account shows `termsVersion` and `currentTerms`.

```json
{
  "error": {
    "type": "entitlement",
    "code": "terms_required",
    "message": "Terms not accepted",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#terms_required"
  }
}
```

## terms_version_mismatch

Wrong terms version. Status 400, type `invalid_request`, not retryable.

When: `accept` (POST /v1/account/terms) or `acceptTerms` (POST /v1/api-keys) names a terms version other than the current one.

Fix: Send the version GET /v1/account returns as `currentTerms`, today "2026-11-01-prototype".

```json
{
  "error": {
    "type": "invalid_request",
    "code": "terms_version_mismatch",
    "message": "Wrong terms version",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#terms_version_mismatch"
  }
}
```

## too_many_keys

Key limit reached. Status 403, type `entitlement`, not retryable.

When: The account already holds 10 active API keys.

Fix: Revoke one at https://map.audio/music (or DELETE /v1/api-keys/{id} signed in there), then create the new key.

```json
{
  "error": {
    "type": "entitlement",
    "code": "too_many_keys",
    "message": "Key limit reached",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#too_many_keys"
  }
}
```

## too_many_endpoints

Webhook endpoint limit reached. Status 403, type `entitlement`, not retryable.

When: The account already has 10 webhook endpoints.

Fix: Delete one with DELETE /v1/webhook-endpoints/{id} (GET /v1/webhook-endpoints lists them), then create the new one.

```json
{
  "error": {
    "type": "entitlement",
    "code": "too_many_endpoints",
    "message": "Webhook endpoint limit reached",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#too_many_endpoints"
  }
}
```

## rotation_in_progress

Secret rotation in progress. Status 409, type `conflict`, not retryable.

When: The endpoint's previous secret is still valid from the last rotation, or another rotation changed the secret at the same moment.

Fix: Rotate again once the time in the message has passed, or delete the endpoint and create a new one.

```json
{
  "error": {
    "type": "conflict",
    "code": "rotation_in_progress",
    "message": "Secret rotation in progress",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#rotation_in_progress"
  }
}
```

## endpoint_disabled

Webhook endpoint disabled. Status 409, type `conflict`, not retryable.

When: The endpoint was disabled after repeated failed deliveries, or because the API key that set its secret was revoked.

Fix: Rotate its secret with POST /v1/webhook-endpoints/{id}/rotate-secret, which enables it again.

```json
{
  "error": {
    "type": "conflict",
    "code": "endpoint_disabled",
    "message": "Webhook endpoint disabled",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#endpoint_disabled"
  }
}
```

## billing_unavailable

Billing unavailable. Status 503, type `unavailable`, not retryable.

When: Plans and render-minutes are not on sale on this stage or not yet, or billing could not be reached. The response's `retryable` is true only in the last case.

Fix: When `retryable` is true, try again shortly; otherwise buy on the production API at https://map.audio/music.

```json
{
  "error": {
    "type": "unavailable",
    "code": "billing_unavailable",
    "message": "Billing unavailable",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#billing_unavailable"
  }
}
```

## subscription_exists

Already subscribed. Status 409, type `conflict`, not retryable.

When: The account already subscribes to a plan.

Fix: Change or cancel the plan from the billing portal (POST /v1/billing/portal, signed in at https://map.audio/music).

```json
{
  "error": {
    "type": "conflict",
    "code": "subscription_exists",
    "message": "Already subscribed",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#subscription_exists"
  }
}
```

## billing_not_available

No billing account yet. Status 409, type `conflict`, not retryable.

When: Nothing has been bought on this account, so there is no billing portal to open.

Fix: Buy a plan or render-minutes first (POST /v1/billing/checkout).

```json
{
  "error": {
    "type": "conflict",
    "code": "billing_not_available",
    "message": "No billing account yet",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#billing_not_available"
  }
}
```

## billing_rate_limited

Too many billing requests. Status 429, type `rate_limit`, retryable.

When: Too many checkout or billing portal links were requested for this account in the last hour.

Fix: Wait the seconds in `Retry-After`; open the link already returned meanwhile.

```json
{
  "error": {
    "type": "rate_limit",
    "code": "billing_rate_limited",
    "message": "Too many billing requests",
    "param": null,
    "retryable": true,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#billing_rate_limited"
  }
}
```

## insufficient_credits

Not enough render-minutes. Status 402, type `entitlement`, not retryable.

When: The job needs more render-minutes than the account has left this month. `details.needed` and `details.remaining` give both.

Fix: Make the job shorter, wait for next month's allowance, or buy render-minutes or a plan at https://map.audio/music.

```json
{
  "error": {
    "type": "entitlement",
    "code": "insufficient_credits",
    "message": "Not enough render-minutes",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#insufficient_credits"
  }
}
```

## concurrency_limit

Too many jobs running. Status 429, type `rate_limit`, retryable.

When: The account's plan runs this many jobs at once (2 on the free plan) and all of them are busy.

Fix: Wait the seconds in `Retry-After`, or for a running job to end (`Prefer: wait`, its events or a webhook), then send again.

```json
{
  "error": {
    "type": "rate_limit",
    "code": "concurrency_limit",
    "message": "Too many jobs running",
    "param": null,
    "retryable": true,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#concurrency_limit"
  }
}
```

## queue_unavailable

Job not queued. Status 503, type `unavailable`, retryable.

When: The job was admitted but could not be queued. Nothing was charged.

Fix: Send the same request again; with the same `Idempotency-Key` it starts the job afresh.

```json
{
  "error": {
    "type": "unavailable",
    "code": "queue_unavailable",
    "message": "Job not queued",
    "param": null,
    "retryable": true,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#queue_unavailable"
  }
}
```

## internal_error

Internal error. Status 500, type `unavailable`, retryable.

When: Something failed on the API's side. Nothing was charged.

Fix: Retry shortly. If it keeps failing, email support@map.audio with the response's Request-Id.

```json
{
  "error": {
    "type": "unavailable",
    "code": "internal_error",
    "message": "Internal error",
    "param": null,
    "retryable": true,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#internal_error"
  }
}
```

## preset_not_found

No such preset. Status 404, type `not_found`, not retryable.

When: No factory preset has this slug or reference. `param` names the field.

Fix: Search with GET /v1/presets?q=<words> and send the `ref` (pam:factory/<slug>) it returns.

```json
{
  "error": {
    "type": "not_found",
    "code": "preset_not_found",
    "message": "No such preset",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#preset_not_found"
  }
}
```

## preset_not_served

Preset not served. Status 400, type `invalid_request`, not retryable.

When: The reference names a pack preset, an MFX preset or an uploaded preset. The API renders factory presets only, and no plan changes that.

Fix: Pick a factory preset: GET /v1/presets lists them.

```json
{
  "error": {
    "type": "invalid_request",
    "code": "preset_not_served",
    "message": "Preset not served",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#preset_not_served"
  }
}
```

## variation_not_found

Variation not in the preset. Status 400, type `invalid_request`, not retryable.

When: The preset has no variation in that slot. The message counts as the field does (`variation` from 1, a DJ set's `variationIndex` from 0) and lists the slots the preset has.

Fix: Use a slot from the message; GET /v1/presets/{id} lists a preset's `variations`.

```json
{
  "error": {
    "type": "invalid_request",
    "code": "variation_not_found",
    "message": "Variation not in the preset",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#variation_not_found"
  }
}
```

## quality_unavailable

Quality not available. Status 400, type `invalid_request`, not retryable.

When: `quality` is elite, which waits for a curated archive of rated presets and no plan unlocks yet.

Fix: Send draft or standard.

```json
{
  "error": {
    "type": "invalid_request",
    "code": "quality_unavailable",
    "message": "Quality not available",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#quality_unavailable"
  }
}
```

## render_too_long

Render too long. Status 400, type `invalid_request`, not retryable.

When: One render would be over 300 s (its length plus tail), or one job over 600 s of audio in all. The message gives the computed length and the fields that set it; `param` names the one to change.

Fix: Lower the field `param` names (bars, seconds, tail, the count of seeds or items), or split the work into more jobs.

```json
{
  "error": {
    "type": "invalid_request",
    "code": "render_too_long",
    "message": "Render too long",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#render_too_long"
  }
}
```

## file_not_ready

File not ready. Status 409, type `conflict`, retryable.

When: The file is still being written by its job (`jobId` names it, `Retry-After` says when to look again), or it is an upload that has not been completed or checked yet.

Fix: Retry once the job named in `jobId` succeeds, or complete the upload first.

```json
{
  "error": {
    "type": "conflict",
    "code": "file_not_ready",
    "message": "File not ready",
    "param": null,
    "retryable": true,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#file_not_ready"
  }
}
```

## file_expired

File no longer stored. Status 410, type `gone`, not retryable.

When: The file expired (outputs are kept 7 days on the free plan) or was deleted, or the account behind a download link was suspended.

Fix: Render it again. GET /v1/files/{id} shows a file's `expiresAt`.

```json
{
  "error": {
    "type": "gone",
    "code": "file_expired",
    "message": "File no longer stored",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#file_expired"
  }
}
```

## download_link_invalid

Download link invalid. Status 403, type `authentication`, not retryable.

When: The signed download link expired (links last an hour) or was altered.

Fix: Ask for a fresh link: GET /v1/jobs/{id} or GET /v1/files/{id}/content.

```json
{
  "error": {
    "type": "authentication",
    "code": "download_link_invalid",
    "message": "Download link invalid",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#download_link_invalid"
  }
}
```

## uploads_disabled

Uploads not open yet. Status 403, type `entitlement`, not retryable.

When: The route needs uploaded files (uploads, project remix, or a command naming an upload), and uploads are not open yet. No plan opens them.

Fix: Render from factory presets (GET /v1/presets), and pass render outputs as files, meanwhile.

```json
{
  "error": {
    "type": "entitlement",
    "code": "uploads_disabled",
    "message": "Uploads not open yet",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#uploads_disabled"
  }
}
```

## upload_closed

Upload closed. Status 409, type `conflict`, not retryable.

When: The upload was already completed, deleted or rejected.

Fix: Start a new upload with POST /v1/uploads.

```json
{
  "error": {
    "type": "conflict",
    "code": "upload_closed",
    "message": "Upload closed",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#upload_closed"
  }
}
```

## upload_expired

Upload window passed. Status 410, type `gone`, not retryable.

When: The upload was not completed within 24 hours of being created.

Fix: Start a new upload with POST /v1/uploads.

```json
{
  "error": {
    "type": "gone",
    "code": "upload_expired",
    "message": "Upload window passed",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#upload_expired"
  }
}
```

## upload_incomplete

Upload parts missing. Status 409, type `conflict`, not retryable.

When: POST /v1/uploads/{id}/complete was sent before every part arrived with its exact size.

Fix: PUT the missing parts (the message says how many arrived), then complete again.

```json
{
  "error": {
    "type": "conflict",
    "code": "upload_incomplete",
    "message": "Upload parts missing",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#upload_incomplete"
  }
}
```

## upload_processing

Upload check starting. Status 409, type `conflict`, retryable.

When: Another completion of this upload is starting its check job.

Fix: Retry after the seconds in `Retry-After`.

```json
{
  "error": {
    "type": "conflict",
    "code": "upload_processing",
    "message": "Upload check starting",
    "param": null,
    "retryable": true,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#upload_processing"
  }
}
```

## checksum_mismatch

Upload does not match its checksum. Status 400, type `invalid_request`, not retryable.

When: A job found that an uploaded file does not match the SHA-256 its upload declared. It arrives in the failed job's `error`.

Fix: Upload the file again with its correct `sha256`.

```json
{
  "error": {
    "type": "invalid_request",
    "code": "checksum_mismatch",
    "message": "Upload does not match its checksum",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#checksum_mismatch"
  }
}
```

## dj_invalid_set

Invalid DJ set. Status 400, type `invalid_request`, not retryable.

When: The DJ set does not fit its schema (https://map.audio/schemas/pam/dj-set.schema.json). `param` names the field, such as set.queue[0].bars.

Fix: Change that field. POST /v1/arrangements checks a set and shows its timing without rendering.

```json
{
  "error": {
    "type": "invalid_request",
    "code": "dj_invalid_set",
    "message": "Invalid DJ set",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#dj_invalid_set"
  }
}
```

## dj_offline_unsupported

Set cannot render as sent. Status 400, type `invalid_request`, not retryable.

When: The set sets `auto` to false. A render steps through the queue on its own.

Fix: Leave `auto` out, or send true.

```json
{
  "error": {
    "type": "invalid_request",
    "code": "dj_offline_unsupported",
    "message": "Set cannot render as sent",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#dj_offline_unsupported"
  }
}
```

## dj_preset_missing

DJ set preset not found. Status 400, type `invalid_request`, not retryable.

When: A preset in the set's queue is not a factory preset. `param` names the item.

Fix: Use references from GET /v1/presets, such as pam:factory/313-disco.

```json
{
  "error": {
    "type": "invalid_request",
    "code": "dj_preset_missing",
    "message": "DJ set preset not found",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#dj_preset_missing"
  }
}
```

## dj_unknown_transition_preset

Unknown transition preset. Status 400, type `invalid_request`, not retryable.

When: A transition names a preset a render cannot use; renders hold only the factory transition presets.

Fix: Pick one from GET /v1/transition-presets, or describe the transition with `bars` and `spec`.

```json
{
  "error": {
    "type": "invalid_request",
    "code": "dj_unknown_transition_preset",
    "message": "Unknown transition preset",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#dj_unknown_transition_preset"
  }
}
```

## invalid_envelope

Invalid state envelope. Status 400, type `invalid_request`, not retryable.

When: An item of `envelopes` is not an object with a `delta` object, or with a `directNodeOps` array and no delta, or its `options` is not an object.

Fix: Send each envelope as {"delta": {...}} or {"directNodeOps": [...]}, with an optional "options" object.

```json
{
  "error": {
    "type": "invalid_request",
    "code": "invalid_envelope",
    "message": "Invalid state envelope",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#invalid_envelope"
  }
}
```

## invalid_batch_line

Invalid batch line. Status 400, type `invalid_request`, not retryable.

When: The engine refused a line of a state batch.

Fix: Change the line the message names.

```json
{
  "error": {
    "type": "invalid_request",
    "code": "invalid_batch_line",
    "message": "Invalid batch line",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#invalid_batch_line"
  }
}
```

## unknown_op

Unknown operation. Status 400, type `invalid_request`, not retryable.

When: The engine was asked for an operation it does not know.

Fix: Check the request against the route's reference.

```json
{
  "error": {
    "type": "invalid_request",
    "code": "unknown_op",
    "message": "Unknown operation",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#unknown_op"
  }
}
```

## invalid_project

Invalid project. Status 400, type `invalid_request`, not retryable.

When: The uploaded project could not be read.

Fix: Export the project again and upload it.

```json
{
  "error": {
    "type": "invalid_request",
    "code": "invalid_project",
    "message": "Invalid project",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#invalid_project"
  }
}
```

## unsupported_project

Project format not supported. Status 415, type `invalid_request`, not retryable.

When: The uploaded project is in a format the engine does not read.

Fix: Upload a supported project format; the remix route's reference lists them.

```json
{
  "error": {
    "type": "invalid_request",
    "code": "unsupported_project",
    "message": "Project format not supported",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#unsupported_project"
  }
}
```

## project_too_large

Project too large. Status 413, type `too_large`, not retryable.

When: The uploaded project is over the engine's size limit.

Fix: Upload a smaller project.

```json
{
  "error": {
    "type": "too_large",
    "code": "project_too_large",
    "message": "Project too large",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#project_too_large"
  }
}
```

## pack_license_required

Pack licence required. Status 403, type `entitlement`, not retryable.

When: The render host refused a preset that needs a pack licence. The API sends only factory presets, so this means a factory preset referenced pack content.

Fix: Pick another factory preset, and email support@map.audio with the Request-Id.

```json
{
  "error": {
    "type": "entitlement",
    "code": "pack_license_required",
    "message": "Pack licence required",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#pack_license_required"
  }
}
```

## license_required

Render host licence check failed. Status 503, type `unavailable`, retryable.

When: The render host's licence check failed. Nothing was charged.

Fix: Retry the job.

```json
{
  "error": {
    "type": "unavailable",
    "code": "license_required",
    "message": "Render host licence check failed",
    "param": null,
    "retryable": true,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#license_required"
  }
}
```

## resource_exhausted

Render host out of resources. Status 503, type `unavailable`, retryable.

When: The render host ran out of memory or another resource. Nothing was charged.

Fix: Retry the job, or make it shorter.

```json
{
  "error": {
    "type": "unavailable",
    "code": "resource_exhausted",
    "message": "Render host out of resources",
    "param": null,
    "retryable": true,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#resource_exhausted"
  }
}
```

## engine_busy

Engine busy. Status 503, type `unavailable`, retryable.

When: The engine was busy with other work. Nothing was charged.

Fix: Retry the job.

```json
{
  "error": {
    "type": "unavailable",
    "code": "engine_busy",
    "message": "Engine busy",
    "param": null,
    "retryable": true,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#engine_busy"
  }
}
```

## render_busy

Renderer busy. Status 503, type `unavailable`, retryable.

When: The renderer was busy with other work. Nothing was charged.

Fix: Retry the job.

```json
{
  "error": {
    "type": "unavailable",
    "code": "render_busy",
    "message": "Renderer busy",
    "param": null,
    "retryable": true,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#render_busy"
  }
}
```

## engine_unavailable

No render host. Status 503, type `unavailable`, retryable.

When: No render host took the job in time, or one failed three times. Nothing was charged beyond a preview already delivered.

Fix: Send the job again; with a new `Idempotency-Key` it starts afresh.

```json
{
  "error": {
    "type": "unavailable",
    "code": "engine_unavailable",
    "message": "No render host",
    "param": null,
    "retryable": true,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#engine_unavailable"
  }
}
```

## timeout

Job deadline passed. Status 504, type `engine`, not retryable.

When: The job ran past its deadline and was stopped. Nothing was charged.

Fix: Make the job shorter or split it.

```json
{
  "error": {
    "type": "engine",
    "code": "timeout",
    "message": "Job deadline passed",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#timeout"
  }
}
```

## engine_failed

Engine failed. Status 500, type `engine`, retryable.

When: The engine failed, or did not write an output it should have. Nothing was charged.

Fix: Retry the job; if it fails again, email support@map.audio with the job id.

```json
{
  "error": {
    "type": "engine",
    "code": "engine_failed",
    "message": "Engine failed",
    "param": null,
    "retryable": true,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#engine_failed"
  }
}
```

## encode_failed

Encoding failed. Status 500, type `engine`, not retryable.

When: A rendered WAV could not be encoded to the requested format. Nothing was charged.

Fix: Render again with format wav, and email support@map.audio with the job id.

```json
{
  "error": {
    "type": "engine",
    "code": "encode_failed",
    "message": "Encoding failed",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#encode_failed"
  }
}
```

## no_candidate_passed

No candidate passed. Status 422, type `engine`, not retryable.

When: A quality: standard search rendered every candidate and none passed the limit gate (silence, clipping, loudness). Nothing was charged.

Fix: Try another seed or preset, or another `search.targetLufs`.

```json
{
  "error": {
    "type": "engine",
    "code": "no_candidate_passed",
    "message": "No candidate passed",
    "param": null,
    "retryable": false,
    "requestId": "8e1f2a3b4c5d6e7f-LHR",
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#no_candidate_passed"
  }
}
```
