Exit codes don't lie to agents. Error messages do.
Your agent runs a command. It fails. The agent reads the error message and tries to fix it. Except the error message is wrong, or misleading, or from a completely different problem that happened 20 minutes ago.
This is the #1 reason coding agents waste time debugging phantom problems.
Here's what I mean. Your agent runs npm test. It sees this:
✗ Authentication test failed Expected: 200 Received: 401 1 failing test
The agent immediately assumes the auth is broken and starts rebuilding the entire authentication system. But if you actually run the tests yourself? They pass. The error message was stale output from a previous run that never got cleared.
Or worse: the agent sees a build error, spends 30 minutes "fixing" webpack config, then discovers the build actually succeeded — it was just showing warnings that looked like errors.
Error messages lie to agents. Exit codes don't.
Here's the pattern that fixes this: teach your agent to verify the actual state, not trust the output.
Before fixing anything:
- Check the exit code:
echo $? - Run a verification command:
npm test -- --reporter=jsonorgit status --porcelain - Look for actual files that should exist if the command worked
- Check timestamps to see if output is fresh
I added this to our coding agent's system prompt:
When a command appears to fail: 1. Check exit code with `echo $?` 2. Re-run with minimal output to verify 3. If exit code is 0, the "error" is likely warnings 4. Only debug if you can reproduce the actual failure
The difference is dramatic. Our agent used to spend 20-30 minutes chasing ghost errors. Now it catches them in under a minute.
Common phantom failures:
- Build warnings that look like errors
- Stale test output in terminal buffers
- Deprecation warnings mixed with success messages
- Progress bars that agents interpret as errors
- Verbose logging that mentions "error" in normal operation
The nuclear option: clear the terminal buffer before every important command. clear && npm test ensures your agent sees fresh output, not yesterday's problems.
Your agent will debug phantom problems until you teach it to verify reality first. Exit codes don't lie. Error messages do.