React error #418 — a hydration mismatch — ran in every visitor's console on the home page for close to two months before anyone looked at it again.
Symptom
A Lighthouse audit against nathandebock.com on 2026-06-04 showed Best
Practices at 96/100 with one failing audit: an uncaught Minified React error #418 in the browser console. Nothing was visibly broken — no layout
shift, no missing content — the tree that failed to hydrate cleanly gets
silently regenerated client-side, so the only symptom was the console
error and the score drop.
Root cause
ProjectCard (components/ui/project-card.tsx) is a client component that
computed formatDaysAgo(project.lastCommitDate) directly during render,
defaulting to new Date() for "now". The home page is statically
prerendered at build time, so the server-rendered HTML freezes that string
— "last commit · 40d ago", say — at whatever "now" was when the site was
last built and deployed. React hydrates the same client component in the
visitor's browser using the browser's actual current date. Any gap between
deploy time and a visitor's first load crosses enough day boundaries to
produce a different string, and React flags the mismatch.
The repo had gone eight weeks without a rebuild by the time this was reinvestigated. The mismatch was not intermittent — it was guaranteed, and it got larger every day the build aged.
Why it wasn't caught earlier
A fix landed the next day (f57b67b, 2026-06-05) addressing a real but
different hydration risk in the Lenis smooth-scroll provider under
prefers-reduced-motion — its commit message specifically notes "no
lenis-class hydration mismatch" as a design goal of that change. That
diagnosis was reasonable given what was visible at the time, and it did
fix a real bug (a stopped-but-still-mounted Lenis instance locking scroll
entirely on long pages), but it was the wrong bug for this error. Nobody
re-ran Lighthouse against production after that fix to confirm error #418
was actually gone, and the repo went dormant three commits later.
Locally, this class of bug is close to unreproducible by construction: a
build followed immediately by a test has server "now" and client "now"
within milliseconds of each other, so the mismatch window never opens.
Every local QA pass before and after f57b67b scored Best Practices
100/100 — correctly, for what was being tested.
Fix
Moved the formatting out of the client component. app/(public)/page.tsx
(a server component, already iterating the project list) now computes
formatDaysAgo(project.lastCommitDate) once and passes the resulting
string down as a staleness prop; ProjectCard renders it without
recomputing anything. There is exactly one computation of the value now,
done server-side, so server and client output cannot diverge — this
removes the bug class, not just this instance of it.
Verified: clean production build, full test suite (95/95), no console errors on a fresh local production server. The specific multi-week-gap trigger can't be reproduced in the same session either way — the fix is verified by eliminating the dual computation, not by re-observing the symptom shrink to zero.
Pattern
This is the second production incident, across two different projects,
whose root cause is "nothing was watching." The webhook incident
documented in /projects/serlei went undetected until
the client manually reconciled sales; this one went undetected until an
unrelated audit reopened the repo. Neither has real monitoring attached —
console.error and a one-off Lighthouse run are not observability. The
fix here closes this specific bug; it does not close the pattern.