Contain the crash before you fix the cause
The site was crashing on every internal link click, and my first instinct was the one that would have cost me the whole evening: open the animation layer, find the exact line moving the node out from under the framework, and fix the architecture right there while the page was on fire. I got about ten minutes into that before I made myself stop and split the job in two.
If your vibe coded site is crashing and you are deciding whether to hotfix it or fix the root cause, the honest answer is you do both, in that order, as two separate changes. Ship the smallest contained workaround that stops the crash on the exact path that triggers it, get the site back up for the people currently hitting a white screen, and only then scope the real structural fix as its own isolated change with its own test. The mistake that eats the evening is treating "stop the crash" and "fix it properly" as one task, because the proper fix is almost always a refactor, and a refactor done live against a broken page is how one outage becomes two.
why shouldn't I just fix the root cause when the site is down?
Because the root cause of a crash like this is usually structural, and structural changes are the worst thing to attempt under outage pressure. When the page is down, your judgment is bad in a specific way: every change feels urgent, so you skip the small verification you would normally run, and you reach for the biggest fix because it feels like the responsible one. That is exactly the moment a refactor goes wide. You move the thing that broke, something two layers away depended on the old shape, now you have a second failure stacked on the first, and you cannot tell which of your changes caused which symptom anymore.
The contained workaround exists to buy back your judgment. Once the site is up, the pressure drops, and the real fix gets to be a normal change: scoped, reviewed, tested on the path that actually breaks, shipped when it is ready instead of when the panic peaks. Isolating the emergency patch from the structural fix is not slower. It is the thing that stops the structural fix from turning into a four-round diagnostic hole while visitors watch a blank screen.
what does a contained workaround actually look like?
Here is the crash, because the shape of it explains the shape of the fix. A hard refresh loaded the site perfectly. Clicking an internal link killed it: white screen, and one console line about a node that could not be removed because it no longer belonged to the node trying to remove it. Same build, same commit. The site worked right up until someone tried to move around inside it instead of just landing on it.
The cause was the scroll animation. To pin a section as the page scrolls past, the animation library wraps that section in a spacer and physically relocates the node in the live DOM, after render, as a side effect the framework never sees. On a hard refresh the browser throws the whole document away, so nothing runs the framework's teardown and nothing trips. On a soft, in-app navigation the framework does the teardown itself, walking the tree it drew at render time and calling removeChild against a map that is now a lie, because the node it recorded has quietly changed parents.
The contained workaround did not touch any of that. It forced the affected routes to do a full document load instead of a soft in-app transition, so the crashing teardown path never ran. That is an ugly fix. It gives up the soft-navigation nicety on those routes and it does nothing about the real disagreement between the two layers. It also stopped the crash in one small, obvious, reversible change, and the site was back up for real visitors inside a few minutes. Ugly and up beats elegant and down every time the page is actually broken.
how do I scope the real fix without it bleeding into the patch?
Write the real fix down as its own change before you touch a line of it, and keep it out of the branch that carries the workaround. The structural problem was that the animation layer was allowed to relocate a node the framework believed it owned, so the real fix was to stop that overlap: pin a wrapper element the animation library owns outright, and never hand it a node the framework is also tracking for teardown. That is a genuine refactor of how the two layers meet, and it deserved its own diff, its own click-through of every internal link on the route, and its own confirmation that soft navigation could be turned back on without the crash returning.
Keeping it separate did two things. It meant the workaround could ship and be reverted independently, so restoring soft navigation later did not mean untangling it from the emergency patch. And it meant the real fix got verified on its own terms instead of being declared done because the site happened to be up, which it already was, on the workaround. This is the same isolation-before-integration discipline that runs through the rest of serious vibe coding and any real AI orchestration: never bundle a structural change with the instrumentation or the patch around it, because when something breaks you want exactly one variable in the diff to blame. Bundle two changes and every failure is now a question of which one did it.
where this discipline comes from
The rule is older than this bug and it is not about crashes specifically. It is: change one structural thing at a time, and never let an emergency patch and an architecture fix ride in the same change. A spec-first habit makes it easy to hold, because naming the property you are fixing (stop the teardown crash) separately from the property you are improving (stop the layers from fighting over the node) turns one vague "fix the site" into two changes you can each verify. A vibe coder who ships fast is not the one who reaches for the biggest fix fastest. It is the one who can tell the difference between stopping the bleeding and closing the wound, and does them in that order, on purpose.
questions that keep coming up
Isn't the workaround just technical debt I'll forget about? Only if you ship it silently. The workaround is debt with a name and a ticket: it exists to buy time for the scoped fix, and the scoped fix is already written down when you ship the patch. Debt you decided to take, with the payoff already scoped, is a plan. Debt you discover later is the problem.
How do I know the crash is structural and not a quick bug? If a hard refresh is clean and a soft navigation crashes, or if the failure only appears on one path and not another, you are almost certainly looking at two layers disagreeing about the same page, which is structural. A quick bug tends to fail the same way everywhere. A path-dependent crash is the tell that something is being torn down against a stale picture.
Won't shipping an ugly workaround make the codebase worse? Briefly, yes, and on purpose. A contained, reversible, well-named workaround for a few minutes of downtime is a far better trade than an open-ended refactor against a live outage. The codebase is worse for a day. The alternative is worse for the visitors right now, and often worse for the codebase too once the panic refactor lands half-finished.
If your vibe coded site crashes on navigation and you want a sparring partner to split the contain-it move from the fix-it move before you touch the architecture, /work-with-us. Send me the crash and the two navigation paths, and we will get the site back up with a workaround you can trust, then scope the real fix as its own change instead of chasing it live. Work with VibeKoded.
// part of the ai websites topic
// grab the free starter kit that makes your AI stop forgetting and stop guessing: get it →
// building with AI? the field manual has the structured lessons.
// hitting this on a real build? this is what I fix →