pytest fail fast: stop on first failure (-x, --maxfail, --ff, --sw)

Run pytest -x to stop at the first failing test, pytest --maxfail=3 to stop after three, pytest --ff -x to rerun last time's failures first and stop at the first one, or pytest --sw to stop and resume from the failing test next run. In the test, --sw exited with code 2, while -x exited with 1.

pytest has four built-in ways to fail fast: -x stops at the first failure, --maxfail=N after N failures, --ff runs last run's failures first, and --sw (stepwise) stops at a failure and resumes from it next time. Measured with pytest 9.1.1 on Python 3.13.5 on six parametrized tests where 3 and 6 fail.

1. -x and --maxfail

$ cat test_ff.py
import pytest

@pytest.mark.parametrize("n", range(1, 7))
def test_n(n):
    assert n % 3 != 0, f"{n} is divisible by 3"
$ pytest --tb=no -q test_ff.py | tail -3; echo "exit ${PIPESTATUS[0]}"
FAILED test_ff.py::test_n[3] - AssertionError: 3 is divisible by 3
FAILED test_ff.py::test_n[6] - AssertionError: 6 is divisible by 3
2 failed, 4 passed in 0.01s
exit 1
$ pytest -x --tb=no -q test_ff.py | tail -3; echo "exit ${PIPESTATUS[0]}"
FAILED test_ff.py::test_n[3] - AssertionError: 3 is divisible by 3
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 2 passed in 0.01s
exit 1
$ pytest --maxfail=2 --tb=no -q test_ff.py | tail -3; echo "exit ${PIPESTATUS[0]}"
FAILED test_ff.py::test_n[6] - AssertionError: 6 is divisible by 3
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 2 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
2 failed, 4 passed in 0.01s
exit 1

-x (same as --exitfirst or --maxfail=1) stopped after test_n[3]; tests 4 to 6 never ran. --maxfail=2 stopped at the second failure, which here was the last test anyway, so all six ran. The exit code stays 1 (tests failed) in both cases.

2. --ff: run the failures from last time first

$ pytest -v --ff --tb=no test_ff.py | grep -E "PASSED|FAILED" | head -4
test_ff.py::test_n[3] FAILED                                             [ 16%]
test_ff.py::test_n[6] FAILED                                             [ 33%]
test_ff.py::test_n[1] PASSED                                             [ 50%]
test_ff.py::test_n[2] PASSED                                             [ 66%]
$ pytest --ff -x --tb=no -q test_ff.py | tail -3; echo "exit ${PIPESTATUS[0]}"
FAILED test_ff.py::test_n[3] - AssertionError: 3 is divisible by 3
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed in 0.01s
exit 1

--ff (--failed-first) reorders, it does not deselect: both earlier failures ran first, then the passing tests. Combined with -x you get the quickest "is it still broken?" answer: 1 failed, nothing else ran. Both need the cache (.pytest_cache); with -p no:cacheprovider they are unavailable.

3. --sw (stepwise): stop, fix, continue from there

$ pytest --sw --tb=no -q test_ff.py | tail -3; echo "exit ${PIPESTATUS[0]}"
FAILED test_ff.py::test_n[3] - AssertionError: 3 is divisible by 3
!!!!!!!! Interrupted: Test failed, continuing from this test next run. !!!!!!!!!
1 failed, 2 passed in 0.08s
exit 2
$ pytest --sw --tb=no -q test_ff.py | tail -3; echo "exit ${PIPESTATUS[0]}"
FAILED test_ff.py::test_n[3] - AssertionError: 3 is divisible by 3
!!!!!!!! Interrupted: Test failed, continuing from this test next run. !!!!!!!!!
1 failed, 2 deselected in 0.07s
exit 2

Stepwise stops at the first failure like -x, but the next run deselects the tests that already passed ("2 deselected") and starts at the failing one. Note the exit code is 2 (interrupted), not 1, so CI scripts that treat 1 as "tests failed" and 2 as "usage/interruption" will see it differently. Use --sw-skip to skip the failing test and stop at the next one.

Related: pytest rerun only failed tests (--lf), pytest exit codes, pytest.raises: get the error message.

Frequently asked questions

How do I make pytest stop on the first failure?

Use pytest -x (or --exitfirst, same as --maxfail=1). pytest --maxfail=N stops after N failures.

What does pytest --ff do?

--failed-first runs the tests that failed in the last run first, then the rest. It reorders but does not deselect; it needs the cache plugin.

What is pytest --sw?

Stepwise mode: stop at the first failure, and on the next run skip the tests that already passed and start from the failing one. It exits with code 2 (interrupted) when it stops.

Written with AI assistance. Measured on 2026-10-23 with pytest 9.1.1 on Python 3.13.5 in a clean virtualenv, starting with an empty .pytest_cache. Each block was run verbatim and the output pasted unedited. PlainHeaders is our extension; pytest is free.