bug(frontend): SvelteKit prerender-crawl bakes redirect-to-login into static HTML for protected routes (HIGH, prod-blocking) #514

Closed
opened 2026-05-11 16:52:24 +02:00 by marcel · 0 comments
Owner

Summary

svelte.config.js lists /hilfe/transkription as a prerender entry. SvelteKit's default prerender.crawl = true then follows nav links from that page and tries to prerender /, /documents, /persons, /geschichten, /stammbaum, … Those routes' load functions throw redirect(302, '/login') when the build-time request has no auth cookie. SvelteKit captures that redirect and emits a static HTML file:

<script>location.href="/login";</script><meta http-equiv="refresh" content="0;url=/login">

These prerendered files (build/prerendered/index.html, build/prerendered/documents.html, etc.) are served before the runtime hooks.server.ts ever runs. So an authenticated user with a valid auth_token cookie still gets the static "redirect to /login" response — every time, forever.

Reproduction (on staging right now)

$ ls /app/build/prerendered/
documents.html  geschichten.html  index.html  persons.html  stammbaum.html  hilfe/

$ head -c 100 /app/build/prerendered/index.html
<script>location.href="/login";</script><meta http-equiv="refresh" content="0;url=/login">

$ curl -H "Cookie: auth_token=Basic <valid>" -o - http://127.0.0.1:3001/
<script>location.href="/login";</script>...   ← same baked HTML, no handler runs

Why local dev works

Vite dev mode doesn't prerender — every request runs through the real handle chain. The bug only manifests in npm run build output.

Impact

  • 🔴 Login impossible from production / staging. Users authenticate successfully (cookie set, 303 to /), but / serves the baked bounce-back HTML and they appear stuck on /login.
  • Affects every protected route reachable via nav from /hilfe/transkription (the only intentional prerender entry).

Fix

// svelte.config.js
prerender: {
    entries: ['/hilfe/transkription'],
    crawl: false   // do NOT follow links and prerender them
}

With crawl: false, SvelteKit only prerenders the explicit entries. The dynamic routes will not be touched at build time.

Discovered

Deploying staging via #497 / #499. Cookie was set correctly, backend accepted the credentials, but every page in the browser bounced back to /login. Inspecting the production build artifacts found the baked HTML files.

## Summary `svelte.config.js` lists `/hilfe/transkription` as a prerender entry. SvelteKit's default `prerender.crawl = true` then **follows nav links** from that page and tries to prerender `/`, `/documents`, `/persons`, `/geschichten`, `/stammbaum`, … Those routes' `load` functions throw `redirect(302, '/login')` when the build-time request has no auth cookie. SvelteKit captures that redirect and emits a static HTML file: ```html <script>location.href="/login";</script><meta http-equiv="refresh" content="0;url=/login"> ``` These prerendered files (`build/prerendered/index.html`, `build/prerendered/documents.html`, etc.) are served **before** the runtime `hooks.server.ts` ever runs. So an authenticated user with a valid `auth_token` cookie still gets the static "redirect to /login" response — every time, forever. ## Reproduction (on staging right now) ``` $ ls /app/build/prerendered/ documents.html geschichten.html index.html persons.html stammbaum.html hilfe/ $ head -c 100 /app/build/prerendered/index.html <script>location.href="/login";</script><meta http-equiv="refresh" content="0;url=/login"> $ curl -H "Cookie: auth_token=Basic <valid>" -o - http://127.0.0.1:3001/ <script>location.href="/login";</script>... ← same baked HTML, no handler runs ``` ## Why local dev works Vite dev mode doesn't prerender — every request runs through the real handle chain. The bug only manifests in `npm run build` output. ## Impact - **🔴 Login impossible from production / staging.** Users authenticate successfully (cookie set, 303 to `/`), but `/` serves the baked bounce-back HTML and they appear stuck on `/login`. - Affects every protected route reachable via nav from `/hilfe/transkription` (the only intentional prerender entry). ## Fix ```js // svelte.config.js prerender: { entries: ['/hilfe/transkription'], crawl: false // do NOT follow links and prerender them } ``` With `crawl: false`, SvelteKit only prerenders the explicit entries. The dynamic routes will not be touched at build time. ## Discovered Deploying staging via #497 / #499. Cookie was set correctly, backend accepted the credentials, but every page in the browser bounced back to `/login`. Inspecting the production build artifacts found the baked HTML files.
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: marcel/familienarchiv#514