fix(home): server-redirect / to /explore + unmask SSR errors#413
Merged
Conversation
Production returns HTTP 500 on the homepage (Cloudflare Pages). Scope is
isolated to the `/` page node: /explore, /recipes, and /membership all 200,
and the 500 shell shows the layout loaded (node_ids:[0,1], membershipEnabled
resolved) — so the Worker, hooks, and layout are fine; only `/`'s page render
throws. The real stack is masked as the generic {message:"Internal Error"}.
Two changes:
(b) Add src/routes/+page.server.ts that throws redirect(307, '/explore'). The
homepage is just a doorway to /explore; redirecting in the server load
short-circuits the response BEFORE any homepage page-component SSR render,
so whatever was throwing in that render path is no longer on the critical
path. Strictly better than SSR-rendering the whole app shell only to
client-redirect in onMount. Validated on the Cloudflare workerd runtime:
/ -> 307 -> /explore -> 200.
+page.svelte: drop the invalid `export const data: PageData = {} as
PageData` (page data must be a settable `export let` prop, not a read-only
const — the one objectively-wrong line on the failing route). Keep an
onMount goto('/explore') as a fallback for in-app navigations to `/`.
(a) Add handleError to hooks.server.ts so the real server-side error + stack
is logged instead of silently masked. Without it, a render/load throw is
invisible in the function logs beyond a bare 500. Client still receives a
generic message; detail stays server-side. This guarantees the next 500
(if any) is diagnosable.
Note: the prod 500 could not be reproduced locally — the exact deployed commit
returns 200 on a faithful workerd build (with and without env vars) — so this
is a validated mitigation, not a confirmed-root-cause fix. handleError closes
that gap going forward.
svelte-check: 0 errors. workerd repro: / 307->200, /explore 200.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ❌ Deployment failed View logs |
zapcooking-frontend | dc0cd7f | Jun 02 2026, 01:22 AM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ❌ Deployment failed View logs |
frontend | dc0cd7f | Jun 02 2026, 01:25 AM |
Contributor
There was a problem hiding this comment.
Pull request overview
Mitigates a production-only SSR failure on the homepage (/) by redirecting requests to /explore before the route’s page component renders, and adds server-side error logging so future SSR failures surface actionable stack traces in function logs.
Changes:
- Add a server
loadon/that throws a redirect to/explore, short-circuiting SSR for the problematic page node. - Remove an invalid
export const datafrom the/page component and keep a client-sidegoto('/explore')fallback for SPA navigation edge-cases. - Add
handleErrorinhooks.server.tsto log real SSR errors (method/path/status/message/stack) while returning a generic client error message.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/routes/+page.svelte | Removes invalid page data export; keeps a client-side redirect fallback. |
| src/routes/+page.server.ts | New server-side redirect from / to /explore to avoid SSR render on the failing node. |
| src/hooks.server.ts | Adds handleError to log SSR errors with stack traces. |
| package.json | Bumps application version. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+8
to
10
| onMount(() => { | ||
| goto('/explore'); | ||
| }); |
Comment on lines
+11
to
+13
| export const load: PageServerLoad = () => { | ||
| throw redirect(307, '/explore'); | ||
| }; |
Comment on lines
+14
to
+16
| method: event.request.method, | ||
| path: event.url.pathname, | ||
| status, |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Production returns HTTP 500 on the homepage (
https://zap.cooking/). This fixes the symptom and ensures any future SSR failure is no longer masked.Investigation (verified, not assumed)
deploy=wrangler pages deploy .svelte-kit/cloudflare; prod headersserver: cloudflare). Repro was done on the real workerd runtime viawrangler pages dev./. Prod:/= 500, but/explore= 200,/recipes= 200,/membership= 200./membershipis also SSR'd through the Worker, so the Worker,hooks.server.ts, and the layout are all fine. The 500 shell showsnode_ids:[0,1]withmembershipEnabledresolved — i.e. the layout loaded and the/page node is what throws.{ message: "Internal Error" }because there was nohandleError.Changes
(b)
src/routes/+page.server.ts(new) —throw redirect(307, '/explore'). The homepage is just a doorway to/explore; redirecting in the serverloadshort-circuits the response before any homepage page-component SSR render, so whatever was throwing in that render path is off the critical path. Also strictly better than SSR-rendering the whole app shell just to client-redirect inonMount.+page.svelte— drops the invalidexport const data: PageData = {} as PageData(pagedatamust be a settableexport letprop, not a read-onlyconst— the one objectively-wrong line on the failing route). Keeps anonMountgoto('/explore')fallback for in-app navigations to/.(a)
src/hooks.server.ts— addshandleErrorthat logs the real error + stack (method, path, status, name, message, stack) while still returning a generic message to the client. Guarantees the next 500 is diagnosable.Verification
pnpm check— 0 errors.wrangler pages devon the adapter-cloudflare build):/→ 307 → /explore → 200;/explore200; no throw in worker stderr.Honest caveat
The prod 500 could not be reproduced locally — the exact deployed commit returns 200 on a faithful workerd build (with and without env vars), so the fault appears prod-environment/artifact specific and I could not capture the real stack (wrangler/Vercel auth unavailable). This is therefore a validated mitigation with ~80% confidence it resolves the symptom, not a confirmed-root-cause fix. Change (a) closes the gap: if anything still 500s after deploy, the stack will be in the function logs.
🤖 Generated with Claude Code