Skip to content

fix(timeline): a warm-up request wedged the server render of every feed page - #827

Merged
github-actions[bot] merged 1 commit into
mainfrom
hotfix/warm-must-not-run-on-the-server
Aug 28, 2026
Merged

fix(timeline): a warm-up request wedged the server render of every feed page#827
github-actions[bot] merged 1 commit into
mainfrom
hotfix/warm-must-not-run-on-the-server

Conversation

@catomean

Copy link
Copy Markdown
Collaborator

Production is currently broken for feed pages. This is the fix.

Symptom

/timeline, /community and /dashboard show a blank page on a fresh load, forever. Signed in, no console error, no failed request, every check green. /post, /settings and /discover render fine.

It is not actually blank — it is the route-level loading.tsx skeleton, which is near-white on a white background, so it reads as an empty page.

Cause — mine, from #826

warmCurrentUserId() is called at the top of every timeline read. Timeline reads also happen during server rendering. It started an unconditional /auth/v1/user request from the server using the browser Supabase client, which carries no request cookies — so it could only ever fail, and it failed while the route was rendering, leaving the segment's Suspense boundary unresolved.

The tell that cracked it: navigating to /timeline from inside the app works (20 posts, no errors) while a fresh load of the same URL hangs. In-app navigation never server-renders.

Fix

The warm is a no-op on the server, and silently so — it is an optimisation, and an optimisation must never be the reason a page fails.

Why I missed it

I verified #826 on the post page and by reading the network waterfall. Neither exercises a cold server render of a feed route. The measurement I trusted was taken on the one path that could not show the bug.

Why the test uses the node environment

Under jsdom window exists, so the guard is never exercised and the test would pass while the server path stayed broken — which is precisely how this shipped. The test asserts typeof window === 'undefined' first, so it cannot silently stop testing anything if the environment changes.

Mutation-proved: removing the guard turns it red; restoring it turns it green.

Ruled out along the way

  • Server: returns complete HTML (49KB) and RSC (25KB) in ~300ms.
  • systemctl restart orangecat-app: no effect.
  • Chunk loading: all 32 chunks 200, none failed.
  • Session: /api/profile returns 200 with the user.
  • Circular imports: session.ts imports only leaf modules.
  • Shell hydration: completes (React props present on buttons).

…ed page

warmCurrentUserId is called at the top of every timeline read, and timeline
reads happen during server rendering too. It started an unconditional
/auth/v1/user request from the SERVER using the BROWSER Supabase client,
which carries no request cookies - so it could only ever fail, and it failed
while the route was rendering.

That is not a wasted request, it is an outage. /timeline, /community and
/dashboard sat on their route-level loading.tsx skeleton forever on a fresh
page load. Navigating to the very same route from inside the app worked,
because that path never server-renders - which is what made it look
intermittent. The skeleton is near-white on a white page, so the symptom
users see is "the timeline is blank". Nothing in the console, no failed
request, every check green.

I introduced this in #826 and did not catch it, because I verified the fix
on the post page and by measuring the network waterfall, neither of which
exercises a cold server render of a feed route.

The warm is now a no-op on the server, silently: it is an optimisation, and
an optimisation must never be the reason a page fails.

The test runs in the `node` jest environment on purpose. Under jsdom
`window` exists, the guard is never exercised, and the test would pass while
the server path stayed broken - which is exactly how this shipped.
Mutation-proved: removing the guard turns it red.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012dpTLxh5GJWeWTF1UEvcD5
@github-actions
github-actions Bot merged commit 5d51628 into main Aug 28, 2026
6 checks passed
@github-actions
github-actions Bot deleted the hotfix/warm-must-not-run-on-the-server branch August 28, 2026 22:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant