vibeapp.win

What brokeUpdated 3 October 2026

Version skew gave a blank health page

A newer frontend read a field that an older backend did not send yet. With no error boundary, one failed read during render blanked the whole app. The skew came from rebuilding a single image, so the fix covered both the UI and the deploy tooling.

The short version

What went wrongA newer frontend read a field that the older backend did not send, and with no error boundary the thrown error blanked the whole app, caused by rebuilding only one image.

How we found itHenning opened the health page on 26 July 2026 and saw a blank page; the cause was traced to the undefined read during render.

The rule nowBuild and deploy the whole stack together, read new backend fields defensively as optional, and wrap the routes in an error boundary.

This post documents something Claude got wrong. The claim rests on a commit or a file, not on memory. All of Claude's mistakes

On 26 July 2026 Henning opened the health page in our wine app and got an empty white page. There was no error message, no header and no navigation.

The repository’s session notes say plainly that this was Henning’s find. Below is what caused it, how we fixed it, and the deploy rule that came out of it.

What was actually wrong

The health page shows a card with AI configuration. A newer version of that card had a section for agent usage: how many scans the app had run in the last 7 days and the last 30 days. The backend supplies those numbers as a small block inside its diagnostics response.

The frontend bundle in production had that newer card. The backend container running next to it was older and did not send the agent-usage block yet. The backend source already had the field. The running container had just not been rebuilt with it.

The fix commit describes the chain: the newer frontend read the 7-day scan count from the agent-usage block, the older backend never sent that block, and “undefined-lesing kastet under render” (the read of undefined threw during render). The frontend had no error boundary, so React unmounted the whole component tree. The result was a blank screen, and not only on the health page: the header and navigation disappeared as well.

The session notes call it “Klassisk type-boundary-felle igjen (stolte på HTTP-payload-form)”. In English: the classic type-boundary trap again, trusting the shape of an HTTP payload. The frontend’s type definition said the block was always there. The type checker believed it, and the running backend broke that promise.

Who did what

Henning writes no code himself, so the card that assumed the field was Claude’s. The repository supports two statements: the frontend trusted a field the backend might not send, and the deploy that caused the skew rebuilt a single service.

How we found the root cause

The session notes record that one thing we saw along the way was expected behaviour and not the bug.

The cause was the one described above: the frontend read a field the backend did not send. That explains the blank page: one exception during render, no boundary to catch it, and the whole tree was gone.

The fix in the frontend

The fix commit landed at 21:39 that evening. It did four things:

  • A new error boundary component. It catches render errors and shows a small error card with the message and two buttons, “Last på nytt” (reload) and “Til forsiden” (go to the front page). The goal is that one broken page shows an error card instead of blanking the whole app.
  • The boundary wraps the routes, not the whole app. The header and navigation sit outside it, so they survive when a single page crashes. A wrapper re-keys the boundary on every route change. Without that, a caught error would stay on screen after you navigated away, because a class-based boundary has no built-in way to reset.
  • The health page reads the new block defensively. If the agent-usage block is missing, the two scan counts show a dash instead of throwing.
  • The type now says the block is optional. A comment next to it explains why: an older backend, from before the agent-usage deploy, leaves it out.

The session notes record one check: the TypeScript compiler ran without errors. They mention no other tests for this fix.

The fix in the deploy tooling

The defensive read and the error boundary handle the symptom. The second commit, at 21:44 the same evening, about five minutes later, goes after the cause.

Its message is direct: the skew came from building only one image, the backend alone. The existing deploy script already did the right thing. It pulls from main, stamps the git commit hash into the build, rebuilds every service together, starts them and runs the database migrations. Its gap was that you could not deploy local changes without a git pull first.

The commit added two things:

  • A no-pull mode in the deploy script. It builds the working tree exactly as it is on disk, and it still rebuilds all services together.
  • A new double-click script for local deploys that runs the deploy script in that mode. Its comments make the same point: building the whole stack together is what matters.

That evening the session notes listed the immediate step: Henning would rebuild the backend so the missing field came back. For full consistency, the regular deploy script should then be run to bring in the frontend fix from main as well. The notes also left an open item: never build a single image in production.

What we take from it

Nothing here was hard to fix once we understood it. What made it bad was the combination. A small mismatch between two versions became a total failure, because the frontend trusted a payload it did not control and had nothing to catch the error. And the mismatch came from rebuilding a single image, while the full-stack deploy script had no simple way to deploy local changes without a git pull.

The rule

Always build the whole stack together: frontend, backend and workers in one deploy, never a single image in production. When the frontend reads a new field from the backend, mark it optional and read it defensively, because for a while the backend running in production may be older than the code. Put an error boundary around the routes, so a broken page shows an error card and not a white screen. And give the full-stack deploy a simple way to ship local changes, so there is no reason to rebuild one service on its own.

Corrections

  1. Attribution corrected: an earlier version said the material did not show who wrote the code and did not put the mistake on Claude. Henning writes no code himself; the code was written by Claude.