Skip to main content

Exit codes

pub enum Exit {
Ok = 0,
TestsFailed = 1,
Error = 2,
}
CodeNameMeaning
0OkEverything selected passed — or nothing was selected
1TestsFailedAt least one test failed or timed out
2ErrorThe run could not be completed

The distinction between 1 and 2 is the useful part: 1 is a finding about your API, 2 is a problem with the run itself.

0 — success

Produced when the run finishes and failed == 0 && timed_out == 0. Skipped tests do not affect it, so all of these exit 0:

  • every test passed
  • a filter matched nothing (snag run -t nonexistent)
  • --dry-run, where everything is skipped
  • --fail-fast skipped the remainder — provided the run had no failure, which in practice means the flag never tripped

Non-run commands exit 0 on success: list after printing, check when everything compiles, init after writing, completions after generating.

A closed stdout pipe is deliberately treated as success — snag list | head exits 0 rather than reporting a broken pipe.

1 — tests failed

At least one test ended failed or timed_out:

  • an assertion failed
  • the script threw, including fail(...)
  • a request could not be completed (DNS, connection refused, TLS)
  • the script file did not exist
  • the test hit its timeout, from the client or the interpreter

The report is complete before the process exits: with --report, the file is written and flushed.

2 — could not run

Anything that prevents a meaningful run. These are configuration or environment problems, and they are worth surfacing differently in CI — a green-turned-red suite is news, a suite that never ran is a broken pipeline.

ConditionMessage
No suite files foundno suite files found (looked for …). Run 'snag init' to create one.
A named path does not existpath does not exist: PATH
A manifest fails to parseparsing suite PATH
Duplicate ids in one fileduplicate test id 'ID' in PATH
Invalid regex in a filterinvalid regular expression in filter
Bad glob patternbad glob pattern 'PATTERN'
Report file cannot be createdcannot write report to PATH: IO ERROR
snag check found compile errorsN of M test(s) failed to compile
snag init would overwritePATH already exists (use --force to overwrite)

All of these print to stderr prefixed with Error: , and nothing is executed.

Using them in CI

#!/usr/bin/env bash
set -uo pipefail

snag tests/ --format junit --report report.xml
code=$?

case "$code" in
0) echo "all green" ;;
1) echo "::error::API regression detected — see report.xml" ;;
2) echo "::error::snag could not run — check suite paths and manifests" ;;
esac

exit "$code"

Do not use set -e around the invocation without capturing $? first: the shell will exit before you can tell 1 from 2.

Deliberate non-errors

Two cases that look like they should fail but do not:

An empty selection. A filter matching nothing exits 0. If a stale -t must break the build, assert on the count:

test "$(snag list tests/ -t smoke -f jsonl | wc -l)" -gt 0 || {
echo "no tests matched -t smoke"; exit 1;
}

A missing script file. That fails the individual test (exit 1) rather than aborting the run, so one broken path does not hide the results of everything else.