A.I. Can't Fix What You Can't Diagnose
An AI agent will happily write a hundred lines of working code and then produce one line that is wrong for the version of the framework you're actually running. That isn't the interesting part — every tool has bugs. The interesting part is what happens next: the agent doesn't know. It has no signal that says "I am stuck." The only thing in the room that can break the loop is a human who recognizes the failure and can name it.
The agent doesn't know when it's stuck
A model's confidence is not calibrated to its correctness. When it generates code for a library it half-remembers — a version whose API shifted after training, a method that got renamed, a value that used to be synchronous and now isn't — the output looks exactly as confident as code it has seen ten thousand times. There is no internal flag that fires.
Give it the error message and it will try things. Sometimes that works. But when the error is a symptom of a version mismatch rather than a logic mistake, the agent tends to attack the symptom: adding a null check, wrapping in a try/catch, restructuring the component. Each attempt is plausible and each one is aimed at the wrong layer, because the agent's mental model of the framework is a version behind and nothing in the error tells it so.
A concrete case: Next.js 15 made route params a promise
This is not hypothetical, and it is checkable. In the Next.js 15 App Router, the params and searchParams props passed to pages and layouts became asynchronous — they're promises now, where in Next.js 14 they were plain objects you could destructure directly. A model trained largely on Next.js 14-era code writes the old form, and the old form breaks.
// Next.js 14 (App Router) — params is a plain object
export default function Page({ params }: { params: { id: string } }) {
return <h1>Product {params.id}</h1>;
}
// Next.js 15 (App Router) — params is a Promise; await it
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
return <h1>Product {id}</h1>;
}
Note the two things that change together: the component becomes async, and the prop gets awaited before you read a field off it. The same applies to searchParams, and to params in generateMetadata.
A developer building an e-commerce app live with Cursor hit exactly this. The generated pages destructured params the old way, the app threw errors, and the agent had no idea why. He recognized the change from his own knowledge of the framework, told the agent to await params everywhere it used them, and the agent went through the codebase and fixed it. Total time: one sentence. The agent could do the work — it could not identify the work.
Your knowledge is the backstop, not the labor
Notice the division of labor in that story. The developer wrote none of the code. He didn't hunt down every file that touched params, didn't refactor the components, didn't write the types. All of that stayed with the agent, which is genuinely good at it.
What he supplied was one thing the agent structurally cannot supply: the diagnosis. He knew which framework version the project was on, knew that version had changed this specific behavior, and could state the fix in a sentence the agent could act on.
That's the shape of the whole relationship. The agent is a fast, tireless, broadly-competent teammate with one hard limitation — it can't flag its own blind spots. You are the part of the system that notices when the output has quietly gone wrong. That job requires knowing the stack, but it requires far less of it than writing everything yourself would.
His own framing, from that session: if I wasn't a developer and didn't know this, I would have been sitting with that error, and I probably wouldn't have been able to proceed.
If you're not a developer, this is the path — not a wall
It's easy to read the above as "you have to be an engineer first." That's the wrong lesson, and it's a discouraging one. The realistic version is narrower and much more achievable: you need enough working knowledge of the specific stack you're building on to recognize when something is off and describe it. Not enough to write the framework. Enough to steer it.
- Know which versions you're on. Read your
package.json(or equivalent). When something breaks weirdly, "what major version is this and what changed in it?" is the first question, and the release notes usually answer it in a paragraph. - Read the migration guide for the major version you're using. Frameworks publish these precisely because breaking changes catch everyone. Twenty minutes with an upgrade guide buys you the vocabulary to name half the bugs an agent will hand you.
- Learn to read the error, not just paste it. You don't need to fix it. You need to notice whether it points at your logic or at how the framework expects to be called — those get different prompts.
- Ask the agent to teach you as it works. "Explain why this needs await" is a free lesson mid-task, and the explanation is usually checkable against the docs in thirty seconds.
- Give the agent the version explicitly. "We're on Next.js 15 App Router" in your rules file or prompt removes a whole class of stale-syntax guesses before they happen.
When to suspect a version problem
- The error appears in framework-generated plumbing (routing, data fetching, config) rather than in your business logic.
- The agent's fixes cycle without converging — three different attempts, same failure.
- The code looks textbook-correct and still fails. That's often the tell: it is textbook-correct, for the previous major version.
- You recently upgraded, scaffolded a fresh project on the latest release, or picked a library that shipped a major version this year.
When those line up, stop asking the agent to fix it and go read what changed. Then hand it the answer.
Building an AI feature? Yeda AI designs, audits, and ships production LLM systems.