Skip to content
Latchkey

pytest Exit Codes in CI - What 0–5 Mean and How to Handle Them

pytest’s exit code tells your pipeline exactly what happened. Knowing the five codes turns a red CI step into a precise diagnosis instead of a guess.

What this error means

A pytest step fails and CI just shows a non-zero exit. The number is meaningful: each code maps to a distinct outcome, from real test failures to a usage error or an empty collection.

Reference
# pytest exit codes
0  All tests passed
1  Some tests failed
2  Test execution was interrupted (e.g. KeyboardInterrupt)
3  Internal error inside pytest
4  pytest usage/command-line error
5  No tests were collected

Common causes

Different codes mean different problems

Exit 1 is genuine test failures; exit 5 is "nothing collected"; exit 4 is a bad command line; exit 2/3 are interruption or an internal pytest error. Treating them all as "tests failed" hides the real cause.

Wrappers can mask the code

Running pytest through a shell pipeline, make, or && chains can swallow or transform the exit code, so CI reports a confusing status.

How to fix it

Inspect the exit code directly

Terminal
pytest; echo "pytest exit: $?"

Handle codes intentionally

  1. Exit 1 → read the failures report and fix the failing tests.
  2. Exit 5 → fix collection/discovery (see the "no tests ran" guide).
  3. Exit 4 → fix the pytest command line or config (bad option/arg).
  4. Exit 2/3 → look for a crash, timeout, or interruption, not assertion failures.

How to prevent it

  • Don’t mask pytest’s exit code behind shell pipelines.
  • Distinguish exit 5 (no tests) from exit 1 (failures) in CI logic.
  • Keep test invocation simple so the exit code reaches the runner unaltered.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →