> ## Documentation Index
> Fetch the complete documentation index at: https://sdk.docs.xano.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Exit codes and outcomes

> What each xanosdk exit code means and what to do next, the JSON failure document every failed command writes, and how to read the completed yes, no or unknown outcome of a release write.

Every `xanosdk` command ends with an exit code, and off a terminal it also writes one JSON
document to stdout. The exit code says *that* something failed; the document says *which* thing.
In a script or CI job, branch on the exit code first and on `error.code` second. Never match on
the message text: messages are reworded between releases, codes are not.

## Exit codes

A failure document's `error.exitCode` always matches the process exit code.

| Code | Meaning | What to do |
| - | - | - |
| `0` | Success. Also a declined confirmation (you typed `n` or pressed Ctrl-D), a `delete` of a name that is already gone (`alreadyGone: true`), and `upgrade --check` when you are current. | Nothing. |
| `1` | A usage error (`SDK_USAGE`: an unknown flag, a missing argument, a local file that is not there, a confirmation needed with no terminal to ask on), a credential the instance refused (`SDK_CREDENTIAL_REJECTED`), a request the instance refused, or anything not listed below. | Read the message. It names the fix. |
| `2` | The command ran and disagreed: a conflict or a refusal. `preflight` or `workspace diff` found a difference, a promote or release did not land as sent, a lock or Xano branch label conflicts, or a guard such as `--expect-live` did not hold. Re-running it unchanged gets the same answer, and `--yes` never waives it. | Fix what it reports. Some refusals name the one flag that accepts the risk, such as `--allow-shared-schema-changes` or `--overwrite`. |
| `3` | `deploy --static`: the backend landed and the static site did not. | Publish the site again with `xanosdk publish`. |
| `4` | `deploy --require-microservices`: a microservice was not ready in time. The backend landed. | Check the microservice. |
| `5` | `test` or `deploy --test`: the suite ran and a test failed. A deploy is not retracted. | Fix the test or the code. |
| `6` | `test` or `deploy --test`: the suite could not be reached, so no test ran. | Check the backend is up, then run the tests again. |
| `7` | `upgrade --check`: a newer `@xano/sdk` is published. | `npx xanosdk upgrade`. |
| `8` | Something the command named, or followed, could not be addressed: a backend that is gone, expired or unreachable, a stopped Xano Engine, a busy import, or a release, profile, Xano branch, test, module, lock entry, `--seed` guid or Engine version that does not exist. Also a network failure or a server error (5xx) before anything was written. | Safe to retry. If an ephemeral expired, deploy a new one. |
| `9` | A write was sent and its answer was lost: a timeout, a dropped connection, a 5xx, or Ctrl-C during the write. It may or may not have happened. | Run the `resolveWith` command before anything else. See [Operation outcome](#operation-outcome). |
| `130` | Ctrl-C (SIGINT) outside a write or an install. | Nothing. |
| `143` | SIGTERM, such as a cancelled CI job or `docker stop`, outside a write. | Nothing. |
| `129` | SIGHUP (the terminal closed) outside a write. | Nothing. |

Codes `3`, `4`, `5` and `6` share a shape: **the deploy itself happened**. Do not re-run the
whole deploy as if nothing landed. A signal that arrives while a write is on the wire ends the run
with `9`, not `130`, `143` or `129`, because what you need to know next is "read before you
retry".

## JSON output

stdout carries one JSON document whenever it is not a terminal, or whenever you pass `--json`.
Progress and messages go to stderr, so a pipe or a CI log step reads clean JSON:

```bash theme={null}
npx xanosdk release list --json
npx xanosdk deploy ./xano/index.ts --ephemeral --test > result.json
```

Three things keep text even when piped: `--help`, `xanosdk version` (so
`$(npx xanosdk version)` works), and a command whose stdout is its data, such as `export` to
stdout or `--path -`. Those write a failure document only under `--json`, because appending one
to the data would corrupt it.

Every date in a `--json` document is ISO 8601 UTC, for example `2026-10-01T09:13:16.000Z`.

## The failure document

A command that fails under `--json`, or with stdout piped, writes this instead of its normal
document, so stdout is never empty:

```jsonc theme={null}
{
  "ok": false,
  "error": {
    "code": "SDK_RELEASE_NAME_TAKEN",
    "message": "A release named \"v1.4.0\" already exists (…). Releases are not replaced — cut a new name.",
    "exitCode": 2,
    "details": { "conflictsWith": { "name": "v1.4.0" } }
  }
}
```

| Field | What it holds |
| - | - |
| `code` | The stable code. Every `SDK_*` code and what it means is in [Warning and error codes](/reference/error-codes#error-codes). |
| `message` | The sentence a person reads, the same one the terminal shows. |
| `exitCode` | The process exit code. |
| `details` | Optional. Always an object, never a bare list: each code's data sits under its own key, beside `warnings` (`{ code, message }` each) when the run printed some. |
| `suggestion` | Optional. The closest match for a mistyped flag or a name that is one slip from a real one (`suggestions` when several are close). |

`SDK_ERROR` is the code for any failure that has no code of its own yet. For those, `exitCode`
tells the kinds apart: `8` for a named thing that is missing or a network failure before any
write, `1` for the rest.

Set `XANOSDK_DEBUG=1` to append the untouched server response to any failure message.

## Operation outcome

The four release writes, `release create`, `promote`, `tenant deploy` and `release transfer`,
answer one question in one shape: does the outcome you asked for exist?

```jsonc theme={null}
{
  "ok": false,                          // only when the run failed, beside `error`
  "operation": "promote",
  "destination": { "instance": "https://your-instance.xano.io", "workspaceId": 3, "kind": "workspace" },
  "release": { "instance": "https://your-instance.xano.io", "workspaceId": 3, "id": 42, "name": "v1.4.0" },
  "branch": "v1.4.0",                   // the Xano branch promote landed on; null for tenant deploy
  "completed": "unknown",               // yes | no | unknown
  "steps": [
    { "name": "land", "completed": "unknown" },
    { "name": "verify", "completed": "skipped" }
  ],
  "resolveWith": "xanosdk workspace branch list --json",
  "resolveSteps": ["If \"v1.4.0\" is absent, nothing landed: re-run as …", "…"],
  "startedAt": "2026-10-13T14:00:00.000Z",
  "resolveNotBefore": "2026-10-13T14:10:00.000Z",
  "error": { "code": "SDK_ERROR", "message": "…", "exitCode": 9 }   // only when the run failed
}
```

| `completed` | Exit | Meaning | What to do |
| - | - | - | - |
| `yes` | `0` | It exists. | Nothing. |
| `no` | non-zero, or `0` when you declined the confirmation | It does not exist. If the run left something behind (a landed Xano branch, a cut it could not delete), `residue` names it and the command that removes it. | Fix the cause and run it again. |
| `unknown` | `9` | The write was sent and the answer was lost. | Run `resolveWith` before anything else. |

Each entry in `steps` has its own `completed`: `yes`, `no`, `unknown`, or `skipped` for a step an
earlier failure kept from running. For `promote`, the `verify` step only checks the landing: a
verification that could not run leaves the landing `yes`.

### Settling an unknown

`unknown` is settled by a read, never by a retry:

1. Run the `resolveWith` command. It is read-only.
2. Follow `resolveSteps`, which says what to do with each answer the read can give.
3. Treat "absent" as proof only after `resolveNotBefore`. Before then the server may still be
   finishing the write.

A blind retry is the one wrong move. The platform stores a release under a taken name with a dash
and four hex characters added (`v1.4.0-a019`) and reports success, so a second `release create`
after a lost answer can leave two releases. A second `promote` lands a second Xano branch.

### Interrupted and declined runs

A run ended by a signal writes `interrupted: true`. With a write on the wire the outcome is
`unknown` (exit `9`); with none it is `cancelled` (exit `130`, `143` or `129`). Either way `landed`
says what the run had already landed.

A declined confirmation exits `0` and still writes its document: the operation commands write the
step as `no`, and the delete commands (`tenant delete`, `ephemeral delete`, `release delete`,
`workspace branch delete`) write `deleted: false, declined: true`.

## Next

* Symptom by symptom, with the fix: [Troubleshooting](/help/troubleshooting).
* Every `SDK_*` code: [Warning and error codes](/reference/error-codes).
* Using exit codes in a pipeline: [CI/CD](/govern/ci-cd).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.