“I Blamed the Wrong AI for My Own Bug”

I’ve got two AI assistants writing code with me these days, and it turns out they both learned the exact same excuse in kindergarten: it wasn’t me.

Bug number one really was Copilot’s fault, no argument, an easy case start to finish. It handed me a query with a capital C sitting where a lowercase variable belonged:

def list_categories_by_id(category_ids) do
  Repo.all(from C in Category, where: C.id() in ^category_ids)
end

Elixir took one look and refused to compile it: binding list should contain only variables or {as, var} tuples, got: C. A capital letter in that spot doesn’t mean “a thing called C.” It means “a module,” the way Category and Repo are modules, and Elixir has zero patience for a variable trying to dress up in a module’s clothes. It’s the code equivalent of signing a business memo in crayon and wondering why nobody took it seriously. My honest reaction at the time, before I’d even found the real cause: “I’ve been fighting CoPilot. It likely did that, and I didn’t know better to correct the case.” Correct instinct, first bug. I found the letter, pointed at it, and walked off feeling like a very satisfied judge banging a gavel on an open-and-shut case.

Bug number two is where I actually learned something, mostly about myself.

A different error showed up later, this time something breaking in how a background process got registered. I marched over and pointed at Copilot with the exact same confidence as before. Case closed, I figured, same defendant, same verdict. Except I was wrong. When I actually sat down and traced it line by line, the real problem was a missing pin operator, a single ^, in a query I’d written earlier that same day with Claude’s help:

def list_order_items_for_order(order_id) do
  OrderItem |> where([i], i.order_id == order_id) |> Repo.all()
end

Elixir’s actual complaint: unbound variable order_id in query. If you are attempting to interpolate a value, use ^var. Here’s what that means in plain English: a bare variable sitting on the left of == reads as “create a brand new binding named this,” not “go check what this variable already equals.” I’d asked Elixir to compare order_id against itself, which it happily agreed to do, which is a wonderful way to write a query that technically compiles and does absolutely nothing useful. The fix is one character:

OrderItem |> where([i], i.order_id == ^order_id) |> Repo.all()

That ^ isn’t decoration. It’s the difference between “here’s a new variable” and “here’s the value this variable already holds, please use it.” And it wasn’t Copilot’s fingerprint anywhere near this one. It was mine and Claude’s, sitting there since that morning, quietly waiting for someone to actually go looking instead of assuming the usual suspect struck twice.

My exact words the second I caught it: “Classic. Blame your Bug 1 on CoPilot when CoPilot can’t defend itself properly. Check your work.” I was right to say it. I was also, at that exact moment, talking entirely to myself.

Here’s the bit that’s actually stuck with me since. Copilot is never going to raise its hand and say “actually, that one’s on me.” Neither is Claude. They don’t compare notes on who wrote what. They definitely don’t rat each other out. Which means the laziest, easiest, most emotionally satisfying move available at any moment is to blame whichever assistant you didn’t personally double-check that day, close the incident report, and walk away feeling vindicated about something that was never actually true.

It’s two kids in the back seat of the minivan, French fries rolling around back there that are pushing four months old at this point, both of them insisting with total sincerity that it was the other one. The parent up front already knows exactly whose fingerprints are on the cookie jar, if they’d bother to look. Except in this version, I’m also occasionally one of the kids, and there are a few more of those fries rolling around up front too, where the responsible adult is supposedly sitting.

That’s the actual job description now, and nobody put it in the AI-tool pitch deck. It was never going to be about typing faster. It’s about being the one honest auditor in a car full of tools that are all, individually, extremely confident it wasn’t them, and being willing to check the seat you’re sitting in too, not just the ones in the back.