Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Exit Codes

stellar-canary’s process exit codes are a stable, documented contract — GitHub automation and other callers rely on them rather than parsing terminal text. They are defined in crates/canary-core/src/errors.rs as the ExitCode enum, and this table matches that source directly (each value is also asserted by that file’s own exit_codes_match_the_documented_contract unit test).

CodeNameMeaning
0PassEvery applicable check passed.
1CompatibilityFailureAt least one fixture’s compatibility assertion failed — a real incompatibility was found.
2ConfigurationErrorInvalid CLI configuration, e.g. a --config path that does not exist, or unparseable configuration. No checks run.
3ExecutionErrorA check could not complete due to an XDR, RPC, or Soroban execution problem — most commonly an unreachable or erroring RPC endpoint. Distinct from a compatibility failure: the check couldn’t run, rather than running and finding a mismatch.
4InvalidFixtureA fixture file failed to load: bad TOML, a missing required field, an unrecognized surface, a duplicate id across the fixture set, or a dangling input_file/expected_file reference.
5InternalErrorAn internal error unrelated to configuration, fixtures, or the three compatibility surfaces (for example, a Git-metadata or local-cache error).

How the mapping works

Every error in the CLI is a CanaryError variant, which is classified into one of four categories, which in turn maps to an exit code:

CanaryError variantCategoryExit code
Configuration, ProjectConfiguration2
FixtureFixture4
Xdr, Rpc, SorobanExecution3
Git, Cache, InternalInternal5

Verified examples

Each of these was captured from a real run of the v0.1.1 binary, not written from memory:

Exit 0 — check against the real Protocol 28 pack: 5/5 applicable checks passed.

Exit 1 — check against a fixture with a deliberately wrong expected value:

error: (terminal output shows "❌ FAIL" and "Status: NOT READY";
the machine-readable status is "fail" — see JSON Report)

Exit 2 — check --config /does/not/exist.toml:

error: configuration error: failed to read configuration file /does/not/exist.toml: No such file or directory (os error 2)

Exit 3 — check with --rpc-url pointed at an unreachable host:

Failure:
p28-rpc-network

failed to call GetNetwork

network transport error calling getNetwork: error sending request for url (...)

Note that in this case the XDR checks still ran and passed (3/3 PASS) — an RPC outage does not block offline checks. status in JSON output is "error", which overrides whatever the pass/fail counts alone would otherwise suggest.

Exit 4 — check against a fixture missing a required field:

error: invalid fixture: failed to parse fixture file /path/bad.toml: TOML parse error at line 1, column 1
  |
1 | id = "demo-missing-field"
  | ^^^^^^^^^^^^^^^^^^^^^^^^^
missing field `description`

Exit 5 is reserved for internal errors (Git metadata or local-cache failures) — this documentation does not fabricate a specific reproduction for it, since triggering one requires an environment fault (e.g. a corrupt local cache file) rather than a normal CLI invocation. Its meaning above is taken directly from the source’s ErrorCategory::Internal mapping, not guessed.