When AI Code Reviews Catch What You Miss
Used deliberately, AI models are surprisingly good at finding the bugs a tired human reviewer skips — off-by-ones, missing awaits, unhandled edge cases. Here is the workflow that makes it reliable.
On this page
A code review is supposed to be a safety net. In practice it is often a formality — especially for the author reviewing their own work, and especially late in a sprint. I have shipped bugs I stared directly at because my brain filled in what the code was supposed to do rather than what it actually did.
AI models are good at the complement of that. They do not know what you intended. They only see what is written, which means they catch a specific class of bugs that humans routinely miss: the gap between intent and implementation.
What models actually catch well
Not everything — which is worth saying upfront. Models are unreliable at catching business logic bugs that require domain knowledge. "This discount should not apply to wholesale accounts" is not something a model can verify from the code alone.
Where they are genuinely useful:
- Missing
awaitin async functions. A function that returns a Promise when the caller expects a resolved value is one of the most common bugs in JavaScript and TypeScript codebases. Models catch it nearly every time. - Off-by-one errors. Slice bounds, loop conditions, index arithmetic. These are mechanical and the model has no preconceived notion of what you meant.
- Unhandled null / undefined. Paths that only reach a null dereference under specific conditions are exactly what a tired reviewer glosses over.
- Error swallowing. Empty
catchblocks, catches that log but do not propagate, async errors that are silently discarded. - Inconsistent validation. Input validated in one path but not another. The model reads all the branches.
A workflow that works
The naive approach — paste the function and ask "does this look right?" — does not work well. You get generic observations and a lot of "this looks correct to me." The model needs a frame.
What I do instead:
Here is the function I am about to merge. Its job is: [one sentence of intent].
It will be called by: [caller context].
What are the top three things most likely to be wrong or cause a bug in production?The key is "most likely to be wrong" rather than "are there any issues." The first forces a ranked, concrete response. The second invites hedged non-answers.
For a full pull request, I paste the diff and add the failure scenario framing:
This diff [brief description].
What is the most plausible way this change causes a production incident?
What input or state would trigger it?Asking it to describe a plausible incident — not just "find bugs" — produces much more actionable output.
What I caught last month doing this
A function that was decrementing a counter before confirming a network request succeeded, meaning a failed request silently corrupted state. I had read the function three times. The model pointed to it in the first response.
A middleware that only validated the Authorization header on POST requests — not PUT or PATCH — because of a copy-paste error in the route registration. I had written the tests but they only covered POST.
Neither of these were complex. Both were the kind of thing that is obvious the moment someone names it. That is the pattern: the model is not smarter than the reviewer, it is less familiar with what the code was supposed to do, which makes it better at reading what it actually does.
The limits
Two things models do reliably wrong in code review:
Race conditions in concurrent code. Without understanding the execution model and what runs in parallel, the model will miss most concurrency bugs or flag things that are not bugs. Do not rely on it here.
Security flaws that require protocol knowledge. Whether a JWT validation is subtly broken, or an OAuth flow has a CSRF gap, requires knowing the spec cold. The model can help as a checklist, but it is not a substitute for a real security review.
The right mental model
Think of the AI reviewer as the colleague who just joined the team. They have not been staring at this codebase for three months. They will ask "why does this function assume the array is sorted?" when you have long since stopped noticing that assumption. That naivety is the value.
Use it for every non-trivial diff before it merges. Do not use it instead of a human reviewer — use it before the human reviewer so the human can focus on the things that actually require judgment.