{"record":{"id":"15ef3ba3bf7f1b5e","repo":"sveltejs/kit","slug":"cannot-prerender-a-root-server-js-that-returns-a","errorCode":null,"errorMessage":"Cannot prerender a root +server.js that returns a non-HTML response - static hosts always serve an HTML file for `${config.paths.base || '/'}`","messagePattern":"Cannot prerender a root \\+server\\.js that returns a non-HTML response - static hosts always serve an HTML file for `(.+?)`","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/kit/src/core/postbuild/prerender.js","lineNumber":538,"sourceCode":"\n\t/**\n\t * @param {'pages' | 'dependencies' | 'data'} category\n\t * @param {Response} response\n\t * @param {string | Uint8Array} body\n\t * @param {string} decoded\n\t * @param {string} encoded\n\t * @param {string | null} referrer\n\t * @param {'linked' | 'fetched'} referenceType\n\t */\n\tfunction save(category, response, body, decoded, encoded, referrer, referenceType) {\n\t\tconst response_type = Math.floor(response.status / 100);\n\t\tconst headers = Object.fromEntries(response.headers);\n\n\t\tconst type = headers['content-type'];\n\t\tconst is_html = response_type === REDIRECT || matches_content_type(type, 'text/html');\n\n\t\tif (!is_html && response.status === 200 && decoded.slice(config.paths.base.length + 1) === '') {\n\t\t\tthrow new Error(\n\t\t\t\t`Cannot prerender a root +server.js that returns a non-HTML response - static hosts always serve an HTML file for \\`${config.paths.base || '/'}\\``\n\t\t\t);\n\t\t}\n\n\t\tconst file = output_filename(decoded, is_html);\n\t\tconst dest = `${config.outDir}/output/prerendered/${category}/${file}`;\n\n\t\tif (written.has(file)) return;\n\n\t\tconst encoded_route_id = response.headers.get('x-sveltekit-routeid');\n\t\tconst route_id = encoded_route_id != null ? decode_uri(encoded_route_id) : null;\n\t\tif (route_id !== null) prerendered_routes.add(route_id);\n\n\t\tif (response_type === REDIRECT) {\n\t\t\tconst location = headers['location'];\n\n\t\t\tif (location) {\n\t\t\t\tconst resolved = resolve(encoded, location);","sourceCodeStart":520,"sourceCodeEnd":556,"githubUrl":"https://github.com/sveltejs/kit/blob/03f1687fe612ce3d2d9131139b5b188d9cf90c64/packages/kit/src/core/postbuild/prerender.js#L520-L556","documentation":"With full prerendering (e.g. adapter-static), the site root must be an HTML page. If your root +server.js handles GET at the base path and returns non-HTML (like JSON), the prerenderer refuses: static hosts map the root path to an HTML file (index.html), so a non-HTML root response cannot be represented on disk.","triggerScenarios":"A root-level `src/routes/+server.js` with `export const GET` returning json()/text (content-type other than text/html, status 200) while the whole app or that route is prerendered.","commonSituations":"adapter-static apps whose root returns an API-style JSON document; converting an SPA into a static build while keeping a JSON root endpoint.","solutions":["Move the JSON response to a nested route like `/api/+server.js` so the root serves an HTML page","Add a root `+page.js`/`+page.svelte` that renders HTML at the base path","Set `export const prerender = false` on the root +server.js route (and keep a separate prerendered root page)","Use an adapter that supports server responses (adapter-node) instead of a static host"],"exampleFix":"// before — src/routes/+server.js\nexport const GET = () => json({ hello: 'world' });\n\n// after — src/routes/api/+server.js\nexport const GET = () => json({ hello: 'world' });\n// plus src/routes/+page.svelte rendering HTML at '/'","handlingStrategy":"validation","validationCode":"// pre-build check in a script\nimport { existsSync } from 'node:fs';\nif (existsSync('src/routes/+server.js')) {\n  console.warn('Root +server.js exists; ensure its GET returns text/html or set prerender = false');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await build();\n} catch (e) {\n  if (String(e.message).includes('root +server.js that returns a non-HTML')) {\n    console.error('Move your root endpoint to /api or add a root +page.svelte');\n    process.exit(1);\n  }\n  throw e;\n}","preventionTips":["Keep JSON/API endpoints under a prefix like /api, never at the root","Always ship a root +page.svelte for static hosts","Audit root-level +server.js files before enabling full prerendering"],"tags":["prerender","adapter-static","routes","html"],"backgroundTag":"prerender-root-non-html-response","analyzedSha":"03f1687fe612ce3d2d9131139b5b188d9cf90c64","analyzedAt":"2026-09-02T02:01:50.504Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}