One Letter Took Down the Whole App

2026-10-08 · 4 min read

One character, in a template file, and the build could no longer produce a page.

Minute forty

FocusBottle has no settings screen. No account, no preferences, no toggle to tune. You pick twenty-five, fifty or ninety minutes and a bottle of light particles reacts to how well you hold your attention. That restraint is not minimalism for its own sake. Every knob you add is a place where a mistake can hide.

Last night I broke my own rule and reached for the phone at minute forty, to check a deploy I had pushed an hour earlier. The page was white. I did not finish the session.

One letter

The change had been small — a table on the trading dashboard I keep, edited at eleven at night. A closing tag lost one letter. That was the entire defect: a single character in a template file, and the bundler could no longer produce a page.

The build refusing to finish is correct behaviour. The trouble is how quiet a refusal looks from outside. The script I run by hand reported no error. The host accepted the upload. Nothing anywhere on the way out said the word failed, and the only component willing to tell the truth was a blank rectangle on my phone.

Three faults, one symptom

The diagnosis cost far more than the fix. I assumed the API was down, because an empty dashboard looks exactly like an empty API. The logs disagreed: the frontend was being handed HTML where it expected JSON. That pointed at a catch-all route bug I had already met once — a single-page-app route registered ahead of the API routes, so anything that did not match got served the index page instead of an answer.

So the error message I was reading had been poisoned by a different bug entirely. And underneath both of those, the backend process was simply dead. Three unrelated failures, all wearing the same white face, and the one that took seconds to fix was the one I found last.

The forty seconds I skipped

The honest root cause is duller than any of it. I never ran the build before committing. In development the frontend is not assembled the same way it is for a deploy, so the code path I had been staring at all evening was not the code path that ships. My checks passed against one system and released the other.

Which is the whole argument for FocusBottle refusing to have a settings screen. Fewer paths means fewer places for one letter to hide. Running the build would have taken forty seconds. The session it cost me was fifty minutes, and the evening was longer. The arithmetic is not close, and I will be doing it in that order from now on.

Engineeringbuild-systemsdebuggingdeveloper-experiencefocus
"A refusal to build and a blank page look identical from the outside. Only one of them is the truth."
Run the build before you commit. The path you develop against and the path you deploy are not the same path, and only one of them is on the internet.