Mistakes Coding Agents Make Frequently
December 21, 2025
React useEffect
Coding agents overuse useEffect because they treat React components like procedural scripts rather than declarative state machines. When an agent sees a requirement like "update X when Y changes," useEffect offers the most literal syntactic translation of that imperative instruction (Trigger -> Action). Agents struggle with the subtler, "React way" of thinking—calculating values during the render pass or handling logic inside event handlers—because those methods require understanding the holistic data flow of the application, whereas useEffect acts as a brute-force patch that can be blindly pasted in to "force" a synchronization without refactoring existing logic.
TypeScript as any forced assertions
Coding agents frequently abuse as any—a forced type assertion that instructs the compiler to completely disable type-checking for a specific variable—because they prioritize silencing the error over strictly adhering to the data contract. When an agent encounters a type mismatch, the "correct" fix often requires tracing the data back to its source or adjusting shared interfaces, tasks that demand a high-level understanding of the project's architecture. Lacking this broader context, the agent treats the error as a mere roadblock to be bypassed; it uses as any to force the code to compile, effectively trading a visible build error for a hidden runtime risk.
Leaving train of thought inline comments
This is a weird one. It seems to leave comments that are useful for PR reviews but not post-merged stuff. Like if you have two code branches and are refactoring to remove one of them, it will leave a trail of thought inline comment like "// Now only requires ..." as if that's useful to future code-readers.
Wrapping everything in try-catch
Agents love to wrap entire functions in a try-catch block where the catch does nothing but log the error and return a generic 500. A route handler is a common example—the agent writes try { ... 50 lines ... } catch (e) { console.error(e); return Response.json({ error: "Something went wrong" }, { status: 500 }) }. This pattern is harmful for several reasons: it bypasses higher-level error handling that frameworks provide, it obscures the original error from observability tools, and it destroys useful control flow. When everything is caught in one place, you lose the ability to distinguish between a validation error (400), an auth failure (401), a missing resource (404), and an actual server crash. The agent does this because "handle errors" is a vague best practice it's been trained on, and wrapping everything in try-catch is the most literal, context-free way to "handle" them—without understanding that sometimes the correct handling is to let the error propagate.
--
I intend to maintain this blog posts as I encounter more of these.