Typeship toolsAPI

Errors and request IDs

One correlation ID on every response, plus an actionable error envelope, stable types and codes, and retry guidance.

Every error uses one envelope, and errors is always an array, so one code path handles every failure:

{
  "errors": [
    {
      "type": "request",
      "code": "input_missing",
      "field": "/name",
      "message": "name is required.",
      "retryable": false,
      "suggested_action": "Supply the required value at field, then retry.",
      "docs_url": "https://typeship.dev/docs/typeship-api/errors#input_missing"
    }
  ],
  "request_id": "req_k3j2h8f0a1b2c3d4"
}
FieldDescription
typeWho can resolve the error. See Error types.
codeStable identifier for the specific failure. Each code belongs to one type and links to its row below.
messageExplanation for a person. Its wording may change; do not parse it.
retryabletrue when another attempt can succeed without changing the request.
suggested_actionStable, concise recovery instruction for a person or agent.
docs_urlLink to this code's row on this page.
fieldJSON Pointer to the input that caused the error, when one did.
inRequest part containing field: body, query, or header. Omitted means body.
phaseOn recorded failures, the stage that failed. See Errors on resources.
target_idThe affected Target when one response reports failures for several Targets.

Handling errors

Branch on type and code, and honor retryable. Use message only for logs and display.

const body = await response.json();
for (const error of body.errors ?? []) {
  if (error.type === "rate_limit" || error.code === "idempotency_key_in_use") {
    await sleep(Number(response.headers.get("Retry-After") ?? 1) * 1000);
    return retry(); // same request, same Idempotency-Key
  }
  if (error.type === "auth") return reauthenticate(error.code); // auth_required, api_key_invalid, token_invalid
  if (error.type === "organization") return askToUpgrade(error.message); // quota_exceeded, feature_not_available
  if (error.retryable) return retryOnceWithBackoff();
  return fix(error.field, error.suggested_action); // change the request before retrying
}
  • Read every entry. A 400 lists up to 50 independent problems so you can fix them in one pass. field is a JSON Pointer into the part named by in; header pointers use lowercase names, such as /idempotency-key.
  • Do not retry plan limits. A capped generation still succeeds and reports omitted operations in coverage. For coverage.reason: "anonymous", offer signup_url; for "free_plan", offer upgrade_url.
  • Wait the stated time. Retry-After gives the seconds to wait on a 429. Responses carry RateLimit-Limit and RateLimit-Remaining, so you can pace before the limit.

The Typeship SDKs raise typed errors carrying this envelope, the Typeship CLI wraps it in its own JSON envelope, and the Typeship MCP server returns it as the tool error.

Error types

TypeMeaningWhat to do
requestThe request cannot be applied as sent: invalid input, a missing resource, or a state conflict.Change the request, or follow the code's recovery for a state conflict.
authThe credential is missing, invalid, or lacks the grant the operation needs.Fix the credential or its grant. Retrying will not help.
idempotencyThe Idempotency-Key is invalid, reused for different input, or still in use.Send a valid or new key, or wait and retry with the same key.
rate_limitToo many requests.Wait for Retry-After, then retry.
organizationThe plan does not include the requested feature or capacity.Change the request or upgrade. Retrying will not help.
sourceA system you own failed: the Spec URL, the connected repository, or the package registry.Check that system, then retry or follow the code's recovery.
apiTypeship failed.Follow retryable, and report the request_id if it persists.

Request errors

Type request.

Input

CodeStatusRetryWhat to do
input_missing400NoSupply the required field named by field.
input_type_invalid400NoSend the value at field with the JSON type the schema requires.
input_format_invalid400NoSend the value at field in the required format, such as an ID with the right prefix.
input_too_long400NoShorten the value at field, or send fewer items.
input_too_short400NoLengthen the value at field, or send more items. An empty string counts as too short.
input_duplicate400NoRemove the repeated items from the array at field.
input_unknown400NoRemove the field the operation does not accept. Misspelled fields are rejected, not ignored.
input_invalid400 or 422NoCorrect the value at field. Covers enum, range, and shape problems, invalid JSON (field: ""), and values that parse but cannot be used.
query_param_invalid400NoRemove the unsupported or repeated query parameter.
cursor_invalid400NoRestart the list without cursor, keeping the same filters for every page.
method_not_allowed405NoUse a method from the Allow response header.
resource_not_found404NoCheck the ID with the matching list operation. A resource in another Organization also returns this.
spec_invalid422NoFix the Spec using the message, which quotes the generator. Warnings never cause this. See Spec errors and warnings.
spec_too_large413NoThe message gives the Spec's size and the limit. Send an inline Spec over 4 MB with spec.url; reduce a Spec over 10 MB across all of its documents.
repository_provider_unsupported422NoUse a GitHub repository.

State

CodeStatusRetryWhat to do
target_busy409YesThe Target is publishing. Wait for it to finish, then retry.
targets_inactive409NoCreate a Target or set one to status: active, then generate again.
resource_changed409YesGet the current resource, reconcile, and retry. Use a new Idempotency-Key for the revised request.
precondition_failed412NoThe ETag in If-Match is stale and nothing was saved. Get the resource again and retry with its new ETag.
delivery_conflict409NoAnother Target owns that repository directory. Choose a different repository or directory.
delivery_exists409NoThe Target already has a Delivery of that type. Update or delete it instead.
resource_has_dependencies409NoDisable the Target to keep its release history, or close its open Draft before deleting it.

Versions and releases

CodeStatusRetryWhat to do
version_invalid422NoUse a SemVer version such as 1.2.0 or 2.0.0-beta.1.
version_occupied409NoThat version is already released. Choose an unused version.
version_too_low422NoChoose a version above the previous release that meets the Draft's version.bump_required.
target_already_released409NoAdoption needs a Target with no release history.
adoption_unverified422NoThe repository tag and published package do not match the version. Check them, then retry adoption.

Publishing

CodeStatusRetryWhat to do
publication_disabled409NoTurn on publish_on_merge on the Target's repository Delivery.
publication_not_retryable409NoNo Publication is queued or failed. Get the release to check each Publication's status.
publication_recovery_unavailable409NoThe release predates reproducible publishing. Merge a new Draft to create a release that can be retried.

Drafts

CodeStatusRetryWhat to do
no_draft409NoThe open Draft has no pending change. Generate the Target first.
draft_merged409NoThe Draft is final. Get the Target and use the Draft named by its draft_id.
customization_conflictOn a DraftNoResolve each conflicted file against the Draft's head_sha. Typeship continues after the last decision.
history_recovery_requiredOn a DraftNoThe default branch history was rewritten. Review the affected files and approve recovery.
checks_failedOn a DraftNoA required check failed on head_sha; the message names it. Open its url in checks, fix the package or check, and push.
checks_unavailableOn a DraftNoA required check could not run. Restore it, then make a reviewed Target change so it runs again.
draft_title_invalidOn a DraftNoEdit the pull request title so it describes the change.

Go SDK dependencies

CodeStatusRetryWhat to do

Authentication errors

Type auth.

CodeStatusRetryWhat to do
auth_required401NoSend an API key or OAuth access token in Authorization: Bearer.
api_key_invalid401NoThe key is invalid, revoked, or expired, or its Organization is gone. Get an active key; revoked keys cannot be restored.
token_invalid401NoThe OAuth access token is invalid or expired. Sign in again.
organization_required403NoReconnect and choose an Organization during OAuth consent.
insufficient_scope403NoReconnect and approve the scope named by WWW-Authenticate, or use an Organization API key.
role_insufficient403NoThe operation is admin-only. Ask an Organization admin; another scope will not help.

Idempotency errors

Type idempotency.

CodeStatusRetryWhat to do
idempotency_key_invalid400NoSend a key of 1 to 255 visible ASCII characters, or omit the header.
idempotency_key_reused409NoThe key was used with different input. Resend the original request or use a new key.
idempotency_key_in_use429After Retry-AfterThe original request is still running. Retry with the same key to receive its response.

Rate limit errors

Type rate_limit.

CodeStatusRetryWhat to do
rate_limit_exceeded429After Retry-AfterWait the Retry-After seconds. See Rate limits.

Organization errors

Type organization.

CodeStatusRetryWhat to do
feature_not_available402NoThe plan lacks the feature named by field, such as the webhook relay. Upgrade, or send the request without it.
quota_exceeded402NoA plan quota is full. Free includes one Project and one active Target per generator. Upgrade, or delete a Project or disable a Target.

Source errors

Type source.

CodeStatusRetryWhat to do
spec_unreachable400, 422, or 502Follow retryableThe Spec URL or a referenced document could not be read. Check the URL, access, and response.
repository_disconnected409NoReconnect the Target's GitHub repository.
repository_unavailable502YesGitHub failed and nothing was saved. Retry; if it persists, check the repository connection and workflow.
publication_failedOn a PublicationNoOpen run_url, fix the workflow or registry failure, then retry the release.

API errors

Type api.

CodeStatusRetryWhat to do
follow_up_failed502YesYour change was saved, but follow-up work did not finish. Get the resource and repeat the same request. See saved-update recovery.
regeneration_failed502Follow retryableYour version selection was saved but generation failed. If retryable, repeat the selection; otherwise fix the cause shown in the Generation.
api_error500 or 502Once, with backoffTypeship failed. Retry once, and report the request_id if it persists. Older recorded failures without a known cause also use this code, with retryable: false.

Errors on resources

Generations, Publications, and Drafts carry an errors array in the same entry shape. On a Generation or Publication each entry also has a required phase:

PhaseMeaning
specTypeship could not read or process the Spec.
generationTypeship could not generate the Target.
deliveryTypeship generated the files but could not complete repository delivery.
publicationTypeship could not start or complete publishing an accepted release.
{
  "id": "gen_7h2p5d9c3m8w1k6q",
  "object": "generation",
  "status": "completed",
  "errors": [
    {
      "type": "source",
      "code": "repository_disconnected",
      "phase": "delivery",
      "message": "Reconnect the GitHub repository parcel-example/parcel-client.",
      "retryable": false,
      "suggested_action": "Reconnect the Target's GitHub repository, then retry the operation.",
      "docs_url": "https://typeship.dev/docs/typeship-api/errors#repository_disconnected"
    }
  ]
}

A completed Generation can carry delivery errors; its files remain available. An empty errors array means no recorded failure. On a recorded failure, retryable describes that failure's cause: true means a new generation or publishing attempt can succeed unchanged, which you start with the operation in suggested_action. Getting the resource does not retry it, and replaying the original Idempotency-Key returns the cached response, so use a new key. When every Target in a Project generation fails, the request itself returns an error envelope with each failure's target_id.

A Draft's errors lists what blocks it while its status is action_required, one entry per finding, such as each failed required check.

Request IDs

Every response carries a server-generated Request-Id header, and every JSON body repeats it as request_id. Responses without a JSON body, such as package downloads, HEAD responses, and redirects, carry it only in the header. Typeship ignores a caller-supplied Request-Id. Include the ID when you report a problem:

curl -sS https://typeship.dev/api/v1/organization \
  -H "Authorization: Bearer $TYPESHIP_TOKEN" -o response.json
jq -r '.request_id' response.json

On this page