# COMA error codes

With `--json`, a failing command writes this to stderr and nothing to stdout:

```json
{
  "apiVersion": "coma.sh/cli/v1alpha1",
  "kind": "Error",
  "requestId": "req_…",
  "error": {
    "code": "machine_not_found",
    "message": "machine \"nope\" not found",
    "retryable": false,
    "details": { "hint": "run `coma machine list`", "machine": "nope" }
  }
}
```

- `error.code` is stable; branch on it. `error.message` is for people.
- `error.retryable: true` means trying again may succeed (for example, the machine was unreachable). Retry once or twice, not in a loop.
- `error.details.hint` names the next command. Other keys depend on the code: `diagnostics` for an invalid `coma.yaml`, `suggestions` for a mistyped command.
- Usage errors (unknown command or flag) use the same envelope with `invalid_argument`.
- A code not listed here maps to exit 1.

"Ask" below means: tell the user what happened and what the fix would do, and wait for a yes.

## Usage and confirmation (exit 2)

| Code | Action |
| --- | --- |
| `invalid_argument` | Fix the command. Check `coma <command> --help` and `details.suggestions` |
| `confirmation_required` | The action needs `--yes`. Ask, then re-run with `--yes` |
| `machine_target_required` | No machine given and the context names none. Ask which machine (`coma machine list --json`), then pass `--machine` |
| `engine_selection_required` | The machine has both engines, or none is chosen. Pass `--engine docker` or `--engine podman`; ask if unsure |
| `workspace_manifest_ambiguous` | Both `coma.yaml` and `coma.yml` exist, or several workspaces share a name. Ask which to keep |
| `workspace_manifest_invalid` | Fix each item in `details.diagnostics` (`file`, `line`, `column`, `path`, `message`); re-check with `coma workspace validate --json` |
| `workspace_target_required` | No machine in `coma.yaml`, `--machine` or the context. Ask which machine; pass `--machine`. Do not commit a machine name to `coma.yaml` unless asked: names are per user |

## Not found (exit 3)

| Code | Action |
| --- | --- |
| `not_found` | Something COMA needs is missing, such as the `coma-sync` helper. Run `coma doctor --json` |
| `context_not_found` | `coma context list --json` |
| `machine_not_found` | `coma machine list --json`. Adding a machine needs the user (host key) |
| `engine_not_found` | The machine has no engine, or not the one asked for. Installing one is `coma machine bootstrap <name> --engine docker`; ask first, and show `--plan` output |
| `endpoint_not_found` | `coma endpoint list --json` |
| `docker_context_not_found` | `coma docker-context list --json` |
| `workspace_manifest_not_found` | No `coma.yaml` here or above. `coma workspace init` writes one; ask before adding files |
| `workspace_not_found` | The workspace was never brought up. `coma workspace up --json` |

## Conflict (exit 4)

| Code | Action |
| --- | --- |
| `already_exists` | For example a `coma.yaml` exists without `--force`. Read the existing one instead |
| `conflict` | The action conflicts with the current state. Read `message` and `hint`; report |
| `context_already_exists`, `machine_already_exists` | Use the existing one, or ask for another name |
| `machine_in_use` | Contexts still use the machine. Removing with `--detach` clears them; ask |
| `endpoint_socket_conflict` | The endpoint's socket path is in use or is not a socket. Report |
| `docker_context_conflict` | A Docker context named `coma` exists that COMA did not create. Ask before `--replace` |
| `docker_context_drifted` | A COMA Docker context was edited outside COMA. Ask before repairing with `coma docker-context install <name>` |
| `local_port_in_use` | A local port is taken by another program or workspace. `coma port list --json` names it. Suggest stopping it, or a `local:` number in `coma.yaml` |
| `workspace_plan_blocked` | Usually `bidirectional` sync without the user's own opt-in. Only the user can enable it (`sync.allowBidirectional: true` in their config, or `COMA_SYNC_ALLOW_BIDIRECTIONAL=1`). Do not set it yourself |
| `workspace_delete_blocked` | `workspace delete --remote` cannot remove the machine's copy. Report |

## Auth and trust (exit 5)

| Code | Action |
| --- | --- |
| `permission_denied` | COMA cannot read or write a local file. Report the path |
| `machine_auth_failed` | SSH login refused. The user must fix keys or `--identity` |
| `ssh_host_key_unknown` | First connection, no terminal. The message shows the fingerprint. Ask the user to confirm it against the server, then re-run with `--host-key SHA256:…`. Never pass it unconfirmed |
| `ssh_host_key_mismatch` | The host key changed since the machine was added. Possibly a reinstall, possibly an attack. Stop and tell the user; never edit `known_hosts` yourself |
| `ssh_key_unavailable` | A private key cannot be read or parsed. Report |
| `bootstrap_privilege_required` | A bootstrap step needs passwordless sudo on the machine. Report |
| `engine_permission_denied` | The SSH user may not use the engine (for example not in the `docker` group). Report |

## Unavailable (exit 6)

Check `error.retryable` first.

| Code | Action |
| --- | --- |
| `machine_unreachable` | SSH cannot reach the machine. Retry once if retryable; otherwise report (machine off, network, firewall) |
| `machine_discovery_failed` | Reached the machine but could not inventory it. Report |
| `ssh_proxy_failed` | The SSH config needs a proxy COMA does not support, such as `ProxyJump`. Report |
| `bootstrap_failed` | A bootstrap step failed. Re-running bootstrap resumes it; ask first |
| `engine_unavailable` | The engine is installed but not working. Report; `coma machine discover <name> --json` refreshes health |
| `endpoint_backend_unavailable` | The engine did not answer through the endpoint. `coma endpoint doctor <name> --json` |
| `daemon_unavailable` | comad is not running. `coma connect --json` (or `coma workspace up --json`) starts it |
| `network_unavailable` | Reserved |

## Timeout (exit 7)

| Code | Action |
| --- | --- |
| `timeout` | Retry once with a longer `--timeout` (for example `--timeout 2m`) |
| `lock_timeout` | Another `coma` process held the state lock. Wait briefly and retry |

## Unsupported (exit 8)

| Code | Action |
| --- | --- |
| `unsupported` | For example a `coma-sync` helper from another release. `coma doctor --json` |
| `machine_unsupported_os` | The machine is not Linux. Report |
| `bootstrap_plan_failed` | Bootstrap cannot plan, for example no apt. Report |
| `sync_mode_unsupported` | `one-way-mirror` and `bidirectional` need the Mutagen sync engine. Check `sync-helper` in `coma doctor --json` |
| `workspace_api_version_unsupported` | `apiVersion` must be `coma.sh/v1alpha1` |
| `workspace_target_kind_unsupported` | `spec.target.pool` and `cluster` are not supported yet; use `machine` |
| `not_implemented` | Reserved |

## Local state and checks (exit 10)

| Code | Action |
| --- | --- |
| `doctor_failed` | A check failed. Read the report on stdout; there is no error envelope |
| `invalid_config` | COMA's config file is invalid. Report the path from `coma doctor --json` |
| `state_corrupt`, `migration_failed` | Local state database problem. Report; do not delete it |
| `state_schema_too_new` | Written by a newer `coma`. The user should upgrade |

## Other

| Code | Exit | Action |
| --- | --- | --- |
| `internal` | 1 | A COMA bug. Report with `coma doctor --json`; adding `--debug` to the failing command includes a stack trace |
| `interrupted` | 130 | Stopped by Ctrl-C or SIGTERM. A remote command may still be running; check `docker ps` |

## Refusals inside Docker errors

When COMA refuses a request from the Docker CLI, Compose or an SDK, the client shows COMA's message with a code in parentheses. These are not `coma` exit codes.

| Code | Action |
| --- | --- |
| `sync_bind_source_unmanaged` | The bind source is outside every synced directory. Use the workspace, or `coma sync watch --path <dir> --json` for a directory that contains it |
| `sync_bind_source_missing` | Sync ignores the path. `coma sync explain <path> --json` names the rule; to sync it, add it to `spec.sync.include` (ask first) |
| `sync_barrier_timeout` | Latest edits had not reached the machine. `coma sync status --json`, then retry |
