The build error that lied

I came back to a build that would not start. An automated run had been working the project overnight, and by morning the dev server was throwing a missing-module error on a package I knew was installed. The import was for gray-matter, the little library that reads the frontmatter on every post like this one. It was in package.json. It was in the lockfile. The build insisted it could not be found.

The reflex, when a dependency is missing, is to install dependencies. So that is what I did, and that is where the morning went sideways.

the error pointed at the wrong thing

A missing-module error feels like it is telling you the truth. The bundler says it cannot resolve gray-matter, so the obvious reading is that gray-matter is not there. I ran an install to put it back. I reached for npm, because npm is the muscle memory, and npm is what an AI build tool reaches for too when you ask it to fix dependencies and do not tell it otherwise.

This repo is a pnpm project. There is a pnpm-lock.yaml sitting in the root, which is the whole declaration of how the dependency tree is supposed to be shaped. npm does not read that file. It built its own flat node_modules on top of a layout that pnpm had arranged as a store of symlinks, and the two ideas of where a package should live started fighting. The build did not come back. Now I had the original failure plus a corrupted tree underneath it. One problem had quietly become two, and the second one was self-inflicted.

the fix that dug the hole deeper

This is the part worth sitting with, because it is the common shape of a vibe coding disaster. The first failure was not my fault. The second one was, and it came from acting before looking. I treated the error message as a diagnosis instead of a symptom. I let the reflex pick the tool. The tool was wrong for this environment, and nothing in the moment forced me to check which package manager the project actually used before I let one rewrite the whole dependency layout.

An AI agent does the same thing faster. Tell it the build is broken and it will run an install to fix it, and it will pick whichever package manager it pattern-matched from training, not the one your lockfile declares. It is confident, it is quick, and it will leave you with a tree that looks installed and resolves to nothing. The speed is the danger. A wrong move executed instantly is just a faster way to a worse state.

look, don't guess

I backed the npm changes out and stopped trying to fix anything. Before another command, I looked at the actual state of the thing the error was complaining about. node_modules/gray-matter was not a real directory. It was a symlink, and it pointed at a path under /tmp that a previous session had created and then thrown away. The package was installed correctly in the pnpm store the whole time. The link to it was stale. It aimed at a location that no longer existed, so every attempt to resolve the module walked off a cliff.

The fix took one line once I could see it. I repointed the link at the real store entry, gray-matter@4.0.3 where pnpm actually keeps it, and the build came straight back. The thing the error had been screaming about was never missing. What was missing was a look.

This is the methodology I keep relearning, and it is worth naming so it transfers: treat observability as an invariant, not a nicety. The surface error is a symptom, and a symptom can lie about its cause. A missing-module error pointed at my import when the fault was a dead symlink in the environment. The discipline is to make the real state observable before you mutate it. Read the lockfile so you know which package manager the project speaks. Look at what a symlink resolves to instead of trusting that it resolves at all. Check what a previous run left behind before you assume the current state is clean. None of that is slower than what I did. Running the wrong install and unwinding it cost an hour. Looking would have cost a minute.

The reason this hits vibe coders specifically is that vibe coding outsources the doing, and the doing is where these stale artifacts get made. It is the same trap as a server that swears it is running the latest code while it serves a stale build: the layer you trust to report reality is quietly out of date, and you act on the report instead of the reality. An agent spins up a temporary path, links against it, moves on, and the link outlives the run. You never see it happen, so when it breaks you have no memory of the cause to draw on. The error is your only witness, and the error is pointing at the wrong suspect. The only way through is to stop reading the symptom as a verdict and go look at the ground truth yourself.

if your AI build keeps failing in ways the error can't explain

If you are a vibe coder and your AI built project keeps breaking in ways the error message cannot quite account for, where reinstalling and re-prompting only seem to add new failures, that is usually not a code problem. It is a visibility problem, a stale or wrong-shaped environment the tooling is lying to you about. If you want a second set of eyes on it, or want the diagnostic discipline wired into your build so the next stale artifact surfaces itself instead of ambushing you, /work-with-us. VibeKoded can find the actual state of a broken AI build, separate the real fault from the self-inflicted one, and leave you with a setup that shows you the truth before you act on it.

The error said the module was missing. The module was right there the whole time. What was missing was a look at the real state, and that is the cheapest fix on the board once you are willing to take it.