Exit codes
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.
| Code | Meaning | Retry? |
|---|---|---|
0 | Success | — |
2 | Usage — no such command, or arguments the parser could not read | No |
3 | A provider or worker is unavailable | Later |
4 | Permission denied, or the provider refused | No |
5 | The daemon could not be reached | Later |
6 | Cancellation failed | No |
7 | A worker timed out | Later |
8 | Version or capability mismatch between CLI, daemon and worker | No |
9 | Conflict — the operation raced another writer | Re-read, then retry |
10 | Every other typed failure, including validation, not-found and timeout | No |
11 | A retryable failure: network, or an operation that says try again | Yes |
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:
| Part | Use |
|---|---|
| Exit code | Branch in a script |
NALA_* code | Identify the specific failure |
remediation | Show 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:
| Code | Means |
|---|---|
DAEMON_NOT_CONNECTED | No daemon reachable |
DAEMON_TIMEOUT | Daemon did not respond in time |
DAEMON_CANCELLED | The call was cancelled |
DAEMON_RPC_ERROR | The 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.