Skip to main content

Exit codes

PreviewAvailable on: WindowsmacOSLinuxShips in the preview channel only. Not a stable release.

What the Harmony CLI returns, and how to branch on it in a script.

The CLI distinguishes failure kinds by exit code so a script can branch on them without parsing text. Text changes between releases; codes are the contract.

The codes

This table is the CLI's own error policy, not a list of codes someone happened to observe. Every typed error the CLI can raise is classified in one place (NALA_COMMAND_ERROR_POLICY), and a cross-repository test fails if this page and that table disagree.

CodeMeaningRetry?
0Success—
2Usage — no such command, or arguments the parser could not readNo
3A provider or worker is unavailableLater
4Permission denied, or the provider refusedNo
5The daemon could not be reachedLater
6Cancellation failedNo
7A worker timed outLater
8Version or capability mismatch between CLI, daemon and workerNo
9Conflict — the operation raced another writerRe-read, then retry
10Every other typed failure, including validation, not-found and timeoutNo
11A retryable failure: network, or an operation that says try againYes

Two things about 10 worth knowing before you branch on it.

It is the catch-all. Most of the CLI's error codes land here, so 10 tells you the command failed in a way the CLI has a name for — read the NALA_* code in the output to learn which. It does not mean "validation error" specifically.

harmony doctor also exits 10, but as a health verdict rather than a command failure: it means one or more probes failed, and the JSON body lists them. A doctor run that exits 0 found nothing wrong.

Error codes are separate from exit codes

A failure carries a named error code alongside the exit status:

Error [NALA_VALIDATION_FAILED]: Invalid arguments for command.
  remediation: The arguments did not match the command schema. (nala:validation)

Three parts worth using:

PartUse
Exit codeBranch in a script
NALA_* codeIdentify the specific failure
remediationShow a human what to do

Prefer the NALA_* code when you need to tell two failures apart. The exit code is deliberately coarse so that a script written today keeps working when a new error code is added to an existing class.

The JSON envelope

--json produces one object on stdout, whatever happens. The envelope is the same shape for success and failure, so a script can parse first and branch after:

{
  "envelopeVersion": 1,
  "command": ["usage"],
  "ok": false,
  "exitCode": 2,
  "error": {
    "code": "NALA_USAGE",
    "message": "Unknown harmony command: usage. Run `harmony help`.",
    "remediationCode": "nala:usage",
    "retryable": false
  },
  "timestamp": "2026-09-19T09:09:23.560Z"
}

exitCode inside the envelope always matches the process exit status, so you can read either. retryable is the same judgement the table above encodes — use it rather than comparing exit codes when you only want to know whether to try again.

Human-readable text goes to stdout when --json is absent, and diagnostics go to stderr in both modes. Parse stdout; log stderr.

Transport failures are their own family

Codes prefixed DAEMON_ mean the CLI could not complete a conversation with the daemon, which is a different problem from a command being wrong:

CodeMeans
DAEMON_NOT_CONNECTEDNo daemon reachable
DAEMON_TIMEOUTDaemon did not respond in time
DAEMON_CANCELLEDThe call was cancelled
DAEMON_RPC_ERRORThe call failed at the daemon

Each carries a retryable flag. Retry transport failures; do not retry validation failures — a malformed command will be malformed the second time.

Scripting

harmony tasks list
if ($LASTEXITCODE -ne 0) {
    Write-Error "harmony tasks list failed with $LASTEXITCODE"
    exit $LASTEXITCODE
}

Bash:

if ! harmony tasks list; then
  echo "harmony tasks list failed with $?" >&2
  exit 1
fi

Branching on retryability, rather than on a specific code:

out=$(harmony tasks list --json) || true
if [ "$(printf '%s' "$out" | jq -r '.ok')" != "true" ]; then
  if [ "$(printf '%s' "$out" | jq -r '.error.retryable')" = "true" ]; then
    exit 75   # EX_TEMPFAIL: a scheduler may run this again
  fi
  printf '%s\n' "$out" | jq -r '.error.message' >&2
  exit 1
fi

IMPORTANT

Do not treat a zero exit as evidence that work finished. harmony tasks list succeeding means the listing succeeded, not that the tasks in it are done. Read task state — see delivery lifecycle.

Instance isolation shows up here

A CLI invocation reaches the daemon matching its own data suffix. If a script runs under a different suffix from the application, it will report transport failures against a daemon that is plainly running.

harmony doctor --json

Compare the resolved data directory. See CLI configuration.