---
title: "Errors"
description: "One actionable error envelope, stable codes, retry guidance, and a request id."
url: https://typeship.dev/docs/typeship-api/errors
markdown: https://typeship.dev/docs/typeship-api/errors.md
section: "API"
---
> ## Documentation index
> Fetch the complete documentation index at https://typeship.dev/llms.txt (every page, one line each) or the full text at https://typeship.dev/llms-full.txt.
> Append .md to any docs URL, or send Accept: text/markdown, for the markdown twin of that page.

# Errors

One actionable error envelope, stable codes, retry guidance, and a request id.

Every error from the typeship API uses the same envelope:

```json
{
  "errors": [
    {
      "type": "request_error",
      "code": "invalid_request",
      "message": "name is required.",
      "retryable": false,
      "suggested_action": "Fix the request using the operation schema, then retry.",
      "docs_url": "https://typeship.dev/docs/typeship-api/errors"
    }
  ],
  "request_id": "req_k3j2h8f0a1b2c3d4"
}
```

`errors` is always an array, even for a single error. `request_id` also arrives on every error response as the `Request-Id` header. Quote it when reporting a problem.

Branch on `type`, `code`, and `retryable`. `message` is for a person and may be reworded. `suggested_action` is a stable recovery instruction. Validation errors can also carry `field` as a JSON Pointer.

## Codes

| Code                     | Status     | Retry               | When                                                                                                                                                                                                             |
| ------------------------ | ---------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `invalid_request`        | 400        | No                  | Malformed JSON, a failed field validation, a bad cursor, or an operation that does not apply. The message names the field.                                                                                       |
| `idempotency_key_reused` | 409        | No                  | The key already identifies a different project-creation request. Reuse the original parameters or send a new key.                                                                                                |
| `unauthorized`           | 401        | No                  | Missing, malformed, expired, or revoked bearer credential. Fix the credential first.                                                                                                                             |
| `organization_required`  | 403        | No                  | The OAuth grant has no organization context. Reconnect and choose an organization during consent.                                                                                                                |
| `insufficient_scope`     | 403        | No                  | The OAuth token lacks the operation's `typeship:read`, `typeship:generate`, or `typeship:write` capability. Reconnect and approve the scope named by `WWW-Authenticate`, or use an organization API key.         |
| `forbidden`              | 403        | No                  | The OAuth token has the capability, but the signed-in organization member is not an admin for an admin-only operation. Ask an organization admin; requesting another scope will not help.                        |
| `plan_limit_reached`     | 402        | No                  | The Project or hosted feature is outside the account's plan. Free has no Generation-count quota or Target-count restriction; each Target is capped to 25 operations. The response names where to lift the limit. |
| `not_found`              | 404        | No                  | The resource does not exist or belongs to another account. The two are indistinguishable on purpose.                                                                                                             |
| `payload_too_large`      | 413        | No                  | A spec over 10MB, inline or fetched.                                                                                                                                                                             |
| `spec_error`             | 422        | No                  | The document cannot be used as a spec at all. The message is the generator's, quoted verbatim. Warnings never cause this. See [Errors and warnings](https://typeship.dev/docs/reference/errors-and-warnings).                        |
| `fetch_error`            | 400 or 502 | 502 only            | The spec URL was invalid (400) or could not be fetched (502): unreachable, timed out after 15 seconds, or answered with an error status.                                                                         |
| `rate_limited`           | 429        | After `Retry-After` | Too many requests. A `Retry-After` header says how long to wait. See [Rate limits](https://typeship.dev/docs/typeship-api/rate-limits).                                                                                              |
| `internal_error`         | 500        | Once, with backoff  | The generator hit an unexpected condition. Not a problem with your spec.                                                                                                                                         |

## Agent guidance

Read `errors[0].code`, never the message. Honor `retryable`; when it is false, change the request or ask the user instead of looping. Three cases deserve care:

* **`plan_limit_reached` and generation caps are not failures to retry.** A capped generation succeeds with a `limits` object. Report omissions only when `omitted_operations` is above zero. For `reason: "anonymous"`, offer `signup_url`. For `reason: "free_plan"`, use `upgrade_url` instead of asking for another key. A 402 means a stored Project or hosted feature is outside the plan.
* **`rate_limited` says how long.** Wait the `Retry-After` seconds once. Anonymous calls also carry `RateLimit-Limit` and `RateLimit-Remaining` on every response, so pace before the wall, not after.
* **Large results are paged and indexed.** A generation over the size cap returns `files_omitted: true` with a `files_index`; fetch the files you need with `GET /v1/generations/{id}/file?path=...` instead of asking for the whole generation again. Lists return `has_more` and `next_cursor`.

The typeship CLI turns all of this into its own envelope with stable codes and `next_steps` (below); the [typeship MCP server](https://typeship.dev/docs/mcp) returns the same bodies as tool errors.

## In the typeship SDK

Nothing throws. Every call returns a discriminated result, and the error side is a typed union of the documented errors for that operation. The envelope is the typed `body`:

```ts
const result = await client.projects.create({
  name: "Acme API",
  definition: { source: { kind: "url", url: "https://api.acme.example.com/openapi.json" } },
  targets: [{ name: "Acme TypeScript SDK", generator: "typescript-sdk" }],
});
if (!result.ok) {
  result.error.status;          // 400
  result.error.body.errors[0];  // typed code, retryability, message, and docs URL
  result.response?.requestId;   // "req_..."
}
```

`PaymentRequiredError`, `NotFoundError`, `UnprocessableEntityError`, and the other documented errors are exported by name. `unwrap(result)` throws them instead.

See [Results and errors](https://typeship.dev/docs/targets/sdk#results-and-errors) for the pattern used by every generated SDK.

## In the typeship CLI

Errors print one JSON envelope on stderr and exit `1`. The envelope contains `status`, `issues`, `docs_url`, `next_steps`, and `detail`.

The API response is available under `detail.body`. CLI issue codes derive from status and error type, including `NO_AUTH`, `PLAN_LIMIT`, `RATE_LIMITED`, and `SPEC_INVALID`.

Usage mistakes exit `2` before making a request. See [Output and exit codes](https://typeship.dev/docs/targets/cli#output-and-exit-codes).

## Sitemap

[Every page of these docs](https://typeship.dev/llms.txt)
