Appendix: Reading Pytest Failures#
A failing test tells you something is wrong. A well-read failure tells you exactly what. The confusion is rarely the tests, it is not knowing how to read the output.
The three categories#
Every pytest failure lands in one of three buckets. The first line tells you which.
Assertion failure. Your code ran and returned a wrong value. Header: FAILED test_foo.py::test_bar - AssertionError. Fix: your code.
Collection error. Pytest could not load the file. Header: ERROR test_foo.py - ImportError or SyntaxError. No tests ran. Fix: an import or typo.
Fixture error. A setup helper blew up before the test body ran. Header: ERROR test_foo.py::test_bar (ERROR, not FAILED), traceback points inside a fixture. Fix: the setup.
Assertion failures: tracing back#
The common trap is a bare AssertionError with no message. Three scenarios hit beginners repeatedly.
Missing await. You wrote result = agent.run(task) instead of await agent.run(task). result is a coroutine object, not a string. assert "Paris" in result throws TypeError: argument of type 'coroutine' is not iterable. Cue: the word coroutine in a failure means a missing await.
Wrong return type. Your function was supposed to return a dict with a content key but returned the raw Anthropic Message object. assert result["content"] throws TypeError: 'Message' object is not subscriptable. Cue: not subscriptable means you are indexing something that is not a dict or list.
Missing dataclass field. A test constructs LoopState(messages=[], iteration=0) and the dataclass was updated to require max_iterations. You see TypeError: __init__() missing 1 required positional argument: 'max_iterations'. Cue: missing positional argument means the signature changed under the test's feet.
The recipe is always the same: read the last traceback frame, not the first. The last frame is your code; everything above is pytest or library internals. Jump there, then read backward.
One example per category#
Assertion. test_basic_loop - AssertionError: assert 3 == 2. Loop ran one iteration too many. Open agent.py, check the while condition: < vs <=.
Collection. ERROR test_tools.py - ModuleNotFoundError: No module named 'swarm.tools.sandbox'. The file is not at that path. Either it was renamed, or pytest is running from the wrong directory and swarm is not on sys.path.
Fixture. ERROR test_dispatch - in fixture 'mock_client', OSError: No such file: '.env'. The fixture loaded env vars from a missing file. Create .env or make the fixture optional. The assertion never ran.
Quick reference#
| Symptom | Likely cause | Where to look |
|---|---|---|
argument of type 'coroutine' is not iterable |
Missing await |
Line before the assert |
'X' object is not subscriptable |
Indexing a non-dict return | Function return statement |
missing N required positional argument |
Signature changed, test stale | Dataclass or function def |
ModuleNotFoundError at collection |
Bad import or wrong cwd | Imports, pytest --rootdir |
SyntaxError at collection |
Typo in test or imported file | File named in the error |
ERROR in a fixture frame |
Setup broke before body | The fixture function |
AssertionError with no message |
Read last traceback frame | Your code, not the test |
TimeoutError in async test |
Coroutine never completed | gather, deadlocks |
AttributeError: NoneType has no attribute X |
Function returned None |
Call just before the access |
When in doubt, pytest -x --tb=short stops at the first failure, then pytest -x --tb=long -s once narrowed shows full context and stdout.