# Errors > The error object, error types and HTTP statuses, which errors to retry, and how to debug with request ids. Source: https://swaglists.com/docs/error-handling Errors use conventional HTTP statuses (`2xx` success, `4xx` a problem with the request, `5xx` a problem on our side) and always have the same JSON body: ```json { "error": { "type": "invalid_request_error", "code": "parameter_invalid", "message": "Invalid items[0].quantity: must be greater than or equal to 1.", "param": "items[0].quantity", "doc_url": "https://swaglists.com/docs/errors#parameter_invalid", "request_id": "req_01k8x4b2q7w9e1r3t5y7u9i1o3", "errors": [ { "param": "items[0].quantity", "code": "parameter_invalid", "message": "Invalid items[0].quantity: must be greater than or equal to 1." }, { "param": "recipient.country_code", "code": "parameter_invalid", "message": "Invalid recipient.country_code: must be an ISO 3166-1 alpha-2 country code." } ] } } ``` | Field | Meaning | | --- | --- | | `type` | Category of the error (table below). | | `code` | Stable, machine-readable code. **Branch on this**, not on the message. Every code is documented in the [error reference](https://swaglists.com/docs/errors.md). | | `message` | Human-readable explanation for developers (not meant for your end customers; wording may change). | | `param` | The parameter at fault, as a path into your request: `recipient.postal_code`, `items[1].sku`, `designs[0].layers[0].url`. | | `doc_url` | Link to the code's documentation. | | `request_id` | Id of the request, also in the `Request-Id` response header. Include it when you contact support. | | `errors` | Validation errors only: **every** problem found in the request (at most 50), each with `param`, `code` and `message`. The first entry is the top-level `code` / `param` / `message`. Fix them all before you retry — a 100-line order with five bad SKUs needs one round trip, not five. | Some errors carry extra fields: | Field | Sent with | Meaning | | --- | --- | --- | | `allowed_values` | a value outside a fixed set (e.g. `unknown_placement`, an enum such as `shipping_method` or the `status` filter) | The values that are accepted. | | `available_shipping_methods` | `shipping_method_unavailable` | The shipping methods you can use for this destination and these items. | | `max_length` | a field that is too long for every way we can fulfill the order | The longest value (in characters) that can be accepted — shorten the field to at most this. | | `max_quantity` | a quantity that is too large | The largest quantity that can be accepted. | | `existing_id` | `duplicate_external_id` | The id of the object that already has this external id. | | `required_amount` / `available_amount` / `currency` | `insufficient_funds` | Credits needed and available (cents). | | `required_scope` | `insufficient_scope` | The scope the API key is missing. | New fields may be added to the error object at any time — ignore the ones you don't use. ## Types and statuses | Status | `type` | Typical codes | Retry? | | --- | --- | --- | --- | | 400 | `invalid_request_error` | `parameter_invalid`, `resource_missing` (a referenced object does not exist), `invalid_json`, business rules like `variant_unavailable` | No — fix the request. | | 401 | `authentication_error` | `missing_api_key`, `invalid_api_key` | No — fix the key. | | 402 | `insufficient_funds_error` | `insufficient_funds` | After adding credits, with a **new** Idempotency-Key ([why](#retries)). | | 403 | `permission_error` | `insufficient_scope`, `live_mode_disabled`, `ip_not_allowed`, `test_mode_only` | No. | | 404 | `not_found_error` | `resource_missing`, `route_not_found` | No. | | 409 | `conflict_error`, `idempotency_error`, `invalid_request_error` | `duplicate_external_id`, `sku_taken`, `idempotency_key_reused`, `idempotency_in_progress`, `order_not_cancelable` | Only `idempotency_in_progress` (and "try again in a minute" cases). | | 413 / 415 | `invalid_request_error` | `request_too_large`, `unsupported_media_type` | No. | | 429 | `rate_limit_error` | `rate_limited` | Yes, after `Retry-After`. | | 500–503 | `api_error` | `internal_error` | Yes, with backoff and the **same** Idempotency-Key. | **404 vs 400 for missing objects:** a 404 means the object in the **URL** does not exist (`GET /orders/ord_unknown`). An unknown object referenced in the **body** (an unknown `sku`, `file_id`, `catalog_variant_id`) is a `400` with `code: resource_missing` and `param` pointing at it. ## Handling errors in code ```js title="Node.js" const res = await fetch("https://swaglists.com/api/v1/orders", { method: "POST", headers, body: JSON.stringify(order) }); const body = await res.json(); if (!res.ok) { const { code, message, param, request_id } = body.error; switch (code) { case "duplicate_external_id": return body.error.existing_id; // already forwarded — treat as success case "resource_missing": if (param?.endsWith(".sku")) return skipUnknownSku(param); // not one of your products break; case "insufficient_funds": return alertFinance(body.error.required_amount, body.error.available_amount); } console.error(`API error ${res.status} ${code} (${param ?? "-"}): ${message} [${request_id}]`); throw new Error(code); } ``` ```python title="Python" res = requests.post("https://swaglists.com/api/v1/orders", json=order, headers=headers) if not res.ok: error = res.json()["error"] if error["code"] == "duplicate_external_id": return error["existing_id"] # already forwarded — treat as success logger.error("API error %s %s (%s): %s [%s]", res.status_code, error["code"], error.get("param"), error["message"], error["request_id"]) raise RuntimeError(error["code"]) ``` ## What to retry - **Retry** network errors, timeouts, `429` (wait `Retry-After` seconds), `409 idempotency_in_progress` (wait 1 second) and `5xx` — with exponential backoff and jitter, and **the same Idempotency-Key**, so a request that actually succeeded is not repeated. See the [retry recipe](https://swaglists.com/docs/idempotency.md#retry-recipe). - **Don't retry** other `4xx` errors unchanged — they will fail again. Fix the request, or surface the problem (log it with `request_id`, alert, or show it in your back office). - **After fixing a `4xx`, send the request with a new Idempotency-Key** — also when the fix happened outside the request, such as adding credits after `402 insufficient_funds` or creating a missing SKU. A request that ran is stored with its key for 24 hours, so a retry with the original key returns the original error again (with `Idempotent-Replayed: true`). Derive the new key from the old one (`order-1042:2`); `external_id` still prevents a duplicate order. ## Validation messages `parameter_invalid` messages name the rule that failed: | Message | Meaning | | --- | --- | | `Missing required parameter: recipient.city.` | Required field absent. | | `Received unknown parameter: items[0].colour.` | Request bodies are strict: unknown fields are rejected (check spelling). | | `Received unknown parameter: updated_since (query parameter).` | Query strings are strict too (only `_`, a cache-buster, is ignored) — see [Pagination](https://swaglists.com/docs/pagination.md). | | `Invalid metadata.note: must not contain NUL characters or invalid (unpaired surrogate) Unicode.` | Text can't contain U+0000 or half of a surrogate pair (a broken emoji, usually from cutting a string by UTF-16 units). Applies to every field, query parameter, path id and the `Idempotency-Key`. | | `Invalid starting_after: must be the id of an object of this list (ids start with "ord_")…` | A cursor from another list. | | `Invalid shipping_method: must be one of: economy, standard, express, priority.` | Wrong enum value. | | `Identify each item with exactly one of product_variant_id, sku, or catalog_variant_id (+ designs).` | Item reference missing or ambiguous. | ## Debugging - Every response has a `Request-Id` header (`req_…`); errors repeat it as `request_id`. - **Developers → Logs** in the dashboard shows recent requests with status, error code, duration and (redacted) bodies — search by request id. - Responses also carry `Api-Version` (the API version that served the request). The complete list of codes, with what each means and how to fix it, is the [error reference](https://swaglists.com/docs/errors.md).