1.1.9 Exit Codes
Exit codes are the part of a Bazel invocation that automation can trust without parsing human-oriented error text. For basic CI, zero versus non-zero is already enough to decide pass or fail, but Bazel goes further and uses different non-zero codes to separate bad flags, interrupted runs, failed tests, and environment trouble.1,2
Start With The Universal Codes
Some exit codes mean the same thing no matter which Bazel command you ran. 0 is success. 2 means the command line is wrong or the environment variables are invalid. 8 means the build was interrupted. 9 means another client held the server lock and you asked Bazel not to wait with --noblock_for_lock.2
The higher-numbered infrastructure-oriented codes cover situations where Bazel itself or its environment failed before you got a normal build result: external-environment failures, Bazel OOM, internal Bazel errors, Build Event Service publishing failures, and remote-cache eviction.2 Not every non-zero exit code means the source code is broken, so scripts should distinguish infrastructure failures from ordinary build failures.
Then Ask Which Command Returned It
bazel build keeps the contract simple: 1 means the build failed.2 bazel test is more informative. It still uses 1 when the build failed, but it uses 3 when the build succeeded and some tests failed or timed out, and 4 when testing was requested but the target pattern matched no tests.2
bazel run is special in a different way. If Bazel finishes the build successfully and the launched program exits non-zero, Bazel returns the program's exit code instead of collapsing everything into one generic Bazel failure.2
bazel query also has its own meanings. Exit code 3 means partial success: Bazel returned some results, but the result is not fully reliable, commonly because --keep_going let query continue past input errors. Exit code 7 means the query command failed.2,3
That makes exit code 3 a good reminder that the command name is part of the contract. With bazel test, 3 means "tests ran, but not all passed." With bazel query, 3 means "you got a partial answer." Whether Bazel stopped early or kept reporting more work with 1.1.5 --keep_going (-k) is a separate question from what the final status code means.
Preserve The Status Before Reading The Log
bazel test //...
status=$?
case "$status" in
0) echo "all tests passed" ;;
3) echo "tests failed or timed out" ;;
4) echo "no tests matched the pattern" ;;
32|33|36|37|38|39|45) echo "Bazel or environment problem" ;;
*) echo "inspect Bazel output and logs" ;;
esac
This keeps the machine-readable signal separate from the human investigation step. For basic CI, non-zero is enough to fail the job.1 As soon as you want smarter retry or triage policy, keep the numeric status, then read the Bazel output, bazel info command_log, and later tools from 5.6 Debugging and 5.6.1 Exit Code Taxonomy.2
Classify First, Diagnose Second
Exit codes tell you what bucket the failure belongs to. They do not replace the
actual error message. A 1 still needs human reading or the phase-based triage
in 2.2.2 Reading Build Output. For first checks you can make when a familiar
message appears, continue with 1.1.10 Common Error Messages.
At Level 1, treat 0 as success, distinguish build failure from test failure, and avoid retrying every non-zero result blindly. The CI-focused version of that habit comes later in 3.6.3 CI-Specific Flags & Exit Codes. Bazel may also introduce more specific non-zero codes over time, so scripts should treat non-zero as failure without assuming today's table is the final one.2
An exit code is Bazel's compact contract with automation. Read it in two steps: first ask whether the code is universal or command-specific, then ask whether it points to broken code, failed tests, or Bazel/environment trouble. The number classifies the failure. The log explains it.
Check your understanding · 3 questions
1.True or false: what does a non-zero Bazel exit code signal?
Choose True or False for each sentence
2.A CI script runs bazel test and gets a non-zero exit code. What is the recommended first step?
Select one answer
3.True or false: how do exit codes relate to Bazel commands?
Choose True or False for each sentence
Footnotes
-
FAQ — basic CI can treat non-zero build/test exit status as failure, without cleaning before every run ↩1 ↩2
-
Calling Bazel from scripts — universal and command-specific exit-code table,
bazel runpassthrough behavior,querypartial success,command_log, and the note that future Bazel versions may add more specific non-zero codes ↩1 ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 -
Query guide —
bazel query --keep_goingcontinues past missing-target and load errors when partial results are acceptable ↩