# Exit codes

The four exit codes espx uses, and the stable error codes that agents and scripts key on.

## Exit codes

| Code  | When                                                                                                               |
| ----- | ------------------------------------------------------------------------------------------------------------------ |
| `0`   | Success, including a `--until` match or the last `--expect` match                                                  |
| `1`   | Any other failure. espx prints one `error:` line on stderr that says what to do next                               |
| `124` | `--timeout` ran out, with the output up to that point still printed (the coreutils `timeout` convention)           |
| `130` | A child process was killed by a signal, usually your `Ctrl+C` reaching cargo or espflash. espx prints nothing more |

`124` comes from `--timeout` on `run`, `monitor` and `replay`, whether or not there was a pattern to wait for. A rejected line (`--reject`) and a stream that ends with an expectation still pending are both `1`.

`espx doctor` reports missing tools in its output and exits `0` either way. Read its `--json` output, or each check's `status`, to fail a script on a missing tool.

## Error codes

Every error espx can raise has a stable code, the same name in snake case across the CLI, the MCP server and the board hub. The CLI prints only the message. The code appears in:

- MCP tool results, as `error.code` in the structured content.
- The agent audit log, as `detail.code` on a denied or failed call.
- The JSON Schema, as the `ErrorCode` type in `schema/espx.json`.

Renaming a code is a breaking change, so these are safe to match on.

### Projects and setup

| Code                       | Meaning                                                                             |
| -------------------------- | ----------------------------------------------------------------------------------- |
| `not_project`              | The directory has no `Cargo.toml`. Run `espx new` or pass `--dir`                   |
| `rust_not_found`           | rustup and cargo are missing                                                        |
| `xtensa_toolchain_missing` | An Xtensa chip or project needs the `esp` toolchain. Run `espx setup --chip <chip>` |
| `unknown_chip`             | Not an id from `espx chips`                                                         |
| `unknown_board`            | Not an id from `espx boards`                                                        |
| `board_chip_mismatch`      | `--board` and `--chip` disagree                                                     |
| `bad_project_name`         | The name is not a valid project name; the message says why                          |
| `project_exists`           | The project folder already exists                                                   |
| `not_a_directory`          | The location is a file, not a folder                                                |
| `dependencies`             | No `Cargo.lock` to read. Build first                                                |
| `tool_missing`             | A tool espx needs is not installed. Run `espx setup`                                |
| `tool_unavailable`         | The mirror publishes no build of a tool for this platform                           |
| `unsupported_platform`     | No espx tools for this OS and architecture                                          |
| `shell_unsupported`        | `--shell` only edits zsh and bash configs                                           |
| `nothing_selected`         | `espx uninstall` with no flag and no `-i`                                           |
| `not_a_tty`                | `-i` without a terminal                                                             |

### Downloads and updates

| Code                | Meaning                                                                         |
| ------------------- | ------------------------------------------------------------------------------- |
| `fetch`             | A download failed                                                               |
| `manifest`          | The release or tool server answered with something espx cannot read             |
| `archive_missing`   | A downloaded archive did not contain the expected binary. Nothing was installed |
| `checksum_mismatch` | A download did not match its SHA-256. Nothing was installed                     |
| `install_failed`    | espx could not replace a binary on disk                                         |

### Builds

| Code              | Meaning                                                       |
| ----------------- | ------------------------------------------------------------- |
| `build_failed`    | cargo reported compile errors, or exited non-zero             |
| `image_too_large` | The image does not fit the app partition. Nothing was flashed |

### Boards

| Code                 | Meaning                                                                                   |
| -------------------- | ----------------------------------------------------------------------------------------- |
| `port_required`      | No board, or several and none chosen. Pass `--port` or bind one                           |
| `board_not_attached` | The board named by a flag or by `[board] id` is not connected                             |
| `board_unreachable`  | espx could not talk to the board; check the cable and that nothing else holds the port    |
| `upload_corrupted`   | The bootloader received corrupted data, typically a WCH bridge on macOS's built-in driver |
| `board_leased`       | Another holder (a flash, an agent) is using the board                                     |
| `board_gone`         | The board did not come back after a flash or reset. Press reset or replug it              |
| `not_attached`       | Nothing is monitoring the board. Attach first                                             |
| `session_closed`     | The monitor session closed. Attach again                                                  |
| `bad_board_name`     | The name has characters a board name cannot have                                          |
| `name_taken`         | Another board already has that name                                                       |

### Monitor and scripts

| Code                 | Meaning                                                                                   |
| -------------------- | ----------------------------------------------------------------------------------------- |
| `bad_pattern`        | A `--until`, `--expect` or `--reject` regex does not compile                              |
| `bad_duration`       | `--timeout` is not a duration like `30s` or `2m`                                          |
| `timeout`            | The timeout ran out (exit `124`)                                                          |
| `monitor_closed`     | The stream ended before the pending pattern matched                                       |
| `rejected`           | A line matched a `--reject` pattern                                                       |
| `monitor_extra_args` | Arguments after `--` on `monitor` together with flags that make espx read the port itself |
| `recording`          | A recording file could not be read                                                        |

### Configuration and agents

| Code                    | Meaning                                                                                                 |
| ----------------------- | ------------------------------------------------------------------------------------------------------- |
| `config`                | `espx.toml` or `boards.toml` has an error; the message names the file, line and key                     |
| `policy_denied`         | The `[agent]` policy does not let an agent do this to this board; the message names the keys to set     |
| `policy_not_editable`   | The `[agent]` policy is written as an inline table or with dotted keys, so espx cannot edit it in place |
| `client_config`         | An MCP client's config file cannot be read or parsed                                                    |
| `client_not_found`      | The `claude` or `codex` CLI is not installed where espx looks                                           |
| `client_command_failed` | `claude mcp add` or `codex mcp add` failed                                                              |
| `espx_not_found`        | The desktop app cannot find the `espx` binary that MCP clients start                                    |

### The board hub

| Code              | Meaning                                                                 |
| ----------------- | ----------------------------------------------------------------------- |
| `hub_unreachable` | The espx process serving the board hub went away. Run the command again |
| `hub_served`      | Another espx process already serves the board hub                       |

### General

| Code             | Meaning                                                                                                   |
| ---------------- | --------------------------------------------------------------------------------------------------------- |
| `command_failed` | A child command failed, or a tool result failed without an espx error (a cancelled job, a rejected `run`) |
| `spawn`          | espx could not start a program                                                                            |
| `env_capture`    | Sourcing `~/.espx/export-esp.sh` failed                                                                   |
| `write_failed`   | A file could not be written                                                                               |
| `delete_failed`  | A file could not be deleted                                                                               |
| `interrupted`    | A child was killed by a signal (exit `130`)                                                               |
| `io`             | Any other I/O error                                                                                       |

The MCP server adds one code of its own, `invalid_arguments`, for a tool call whose arguments do not match the tool's schema.

## Related

- [Scripts and CI](https://www.espx.dev/docs/cli/scripting)
- [MCP server](https://www.espx.dev/docs/agents/mcp)
- [JSON events](https://www.espx.dev/docs/reference/events)
