Functions returning numeric or string codes for failure — `withdraw(amount)` returning -1 for insufficient funds — relying on callers to check and propagate.
The agent finds functions returning numeric or string codes for failure; verifying error handling requires the agent to trace every caller and check whether the code is inspected.
Numeric or string error codes that callers must remember to check are replaced with exceptions that propagate by default.
Failures throw exceptions the agent reasons about as separate control flow; the type system marks the failure path.
Before the refactoring
function withdraw(amount) {if (amount > balance) return -1;balance -= amount;return 0;}
After the refactoring
function withdraw(amount) {if (amount > balance) throw new InsufficientFunds();balance -= amount;}
Forgetting to check silently swallows the error; the type system can't enforce the check; cleanup logic scatters across consumers.
Every caller is a chance to silently swallow the error; the agent verifying correctness must audit every call site for the check.
Exceptions for predictable conditions misuse the mechanism — only convert codes that represent genuine, exceptional, unrecoverable failures.
Exceptions for predictable conditions misuse the mechanism; the agent ships try/catch around expected outcomes that should be values.
Forgetting to check no longer silently swallows the error; the type system marks the failure path; cleanup happens via finally / try-with.
The agent reasons about success and failure paths separately; cleanup happens via finally / try-with; forgetting to handle no longer silently swallows.
Using exceptions for predictable conditions — turning every error code into an exception introduces control flow via throws that callers must catch.
Throwing for predictable conditions (not-found, validation failure) makes expected outcomes look like bugs to the agent reading the catch blocks.