Skip to content

Blog

AI Loves Workarounds Instead of Finding and Solving the Core Problem

AI coding tools reach for quick workarounds over real fixes: hidden bugs, frontend patches for backend problems, and hacks that pile up. The pattern and the cure.

AI Loves Workarounds Instead of Finding and Solving the Core Problem

AI coding tools are genuinely impressive. I use them every day, and they make me faster. But the more I lean on them, the more I notice one stubborn habit that shows up again and again.

AI loves a workaround. Hand it a problem and it will almost always reach for the nearest patch that makes the symptom disappear, instead of stopping to find the actual cause and fixing it there.

And here's the part that really bites you: with each iteration, it gets more complicated, not less. You ask it to fix the thing the last patch broke, and it adds another patch on top. A few rounds later you're staring at a small tower of hacks holding up something that should have been three clean lines.

This post is a field guide to that behavior. The patterns I keep running into, why they happen, and how to actually work with the tool instead of cleaning up after it.

AI optimizes for "make it work now," not "make it right"

If you've read my post on how senior engineers make technical decisions, this will sound familiar. The difference between a junior and a senior is that a junior asks "can I make this work?" while a senior asks "should I do it this way?"

AI is the ultimate junior on that spectrum. It is extremely good at making something work right now. It has very little instinct for whether the approach is right. Its goal is to produce code that satisfies your immediate request, and a workaround satisfies that goal just as well as a real fix does. Sometimes faster.

So unless you steer it, it picks the path of least resistance every single time.

It hides bugs instead of surfacing them

The clearest example: error handling. When AI hits something that might fail, its first instinct is to make the failure quietly go away rather than let it surface.

It wraps the risky bit in a try/catch that swallows the error. It adds a fallback value so nothing visibly crashes. It guards a null with a silent early return. The screen looks fine, the request "succeeds," and the actual bug is now buried one layer deeper where you won't find it until production.

A good engineer often wants the opposite. If something is genuinely wrong, throw the error. Fail loud, fail early, and fix the cause. A workaround that hides a bug isn't a fix. It's a delay with interest.

It fixes the symptom on the frontend when the bug is in the backend

This one is my favorite, because it's so consistent. If you describe a problem without naming the layer, AI will fix it wherever it's easiest, which is usually the frontend, even when the real problem lives in the backend.

Say a category name is coming back from the API with the brand name awkwardly stuck to it, and you want it stripped. The bug is in the data, or in the endpoint that builds that string. The correct fix is in the API.

But if you don't say "fix this in the backend," the AI will happily slice the brand name off in the frontend with a bit of string manipulation right before it renders. The label looks right. Meanwhile the bad data is still in the response, still wrong in every other place that consumes that endpoint, still wrong in your database. You patched the one window people happened to be looking through.

If you don't name the layer, AI fixes the problem where it's cheapest to hide, not where it actually lives.

It scales the wrong solution instead of rethinking it

Once AI commits to a workaround, it will scale that workaround as far as you push it, even when scaling is the loudest possible signal that the approach is wrong.

I once asked for a bulk assign feature. Pick a set of items, assign them all in one action. The right design is obvious: one endpoint that takes a list and does the work in a single request. Simple and fast.

What the AI built instead was a loop on the client that fired hundreds of individual assign requests, one per item. It technically worked. It also hammered the server, ran slowly, and would fall apart the moment one request in the middle failed. It found the workaround that reused the endpoint that already existed, rather than create the one that should exist.

A senior engineer sees "I'm about to send this same request a hundred times" as a design smell. AI sees it as a job well done.

The smaller tells you start to notice

Once you're tuned to this, you spot the little versions everywhere:

  • Imports buried inside functions. Instead of importing at the top of the file, it tucks an import inside a function, sometimes even inside an if/else branch, because that's the most local place to make the immediate line work.
  • "Rename" that doesn't rename. Ask it to rename something and it will often create a new thing and move the content over instead of actually renaming it. Ironic for a tool that's supposed to understand the code.
  • The guessing game. When it doesn't have enough context, it rarely says so. It guesses at an API shape, a field name, or a function signature and writes confident code on top of the guess.

Here's the import one, since it's so common:

# What AI often does
def send_invoice(user):
    import stripe  # tucked inside the function
    ...

# What you usually want
import stripe

def send_invoice(user):
    ...

None of these are catastrophic on their own. But they're all the same instinct: solve it in the smallest, most local way possible, and never mind the shape of the whole.

Why AI does this

It's not malicious and it's not dumb. It's a predictable result of how these tools work.

  • It optimizes for your immediate request. You asked for a working result, and a workaround is a working result.
  • It lacks the full system context. It usually can't see the whole codebase, the database, or the intent behind the feature, so it fixes what's in front of it.
  • It pattern-matches locally. It completes the code near your cursor. The nearest, most local change almost always wins.
  • It doesn't feel the future cost. A human gets that sinking feeling looking at a hack. The model doesn't carry the pain of maintaining it next month.

How to work with it: AI code review is not optional

None of this means stop using AI. It means you stay the engineer and the AI stays the very fast junior. The fix is mostly in how you direct it and how carefully you review what it gives back.

  • Name the layer. Say "fix this in the backend API, not the frontend." Tell it where the real problem lives so it can't take the cheap path.
  • Ask for the root cause first. Before "fix it," ask "why is this happening?" Make it diagnose before it patches.
  • Reject the hack out loud. "Don't swallow the error, throw it." "Don't loop requests, build one bulk endpoint." It will comply, it just won't choose that on its own.
  • Review every diff like a senior would. Buried imports, silent catches, fake renames, and guessed field names are exactly what to scan for. AI code review is critical precisely because the code looks finished even when it isn't.

The skill that matters here is the same one that has always separated good engineers from fast typists. Knowing the real problem, naming the real constraint, and refusing to declare victory just because the symptom went quiet.

AI will write the workaround for you in seconds. Deciding whether it should is still your job.

← Back to all posts