{"record":{"id":"f338197081900a35","repo":"withastro/astro","slug":"server-error","errorCode":null,"errorMessage":"Server error","messagePattern":"Server error","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"packages/integrations/node/src/middleware.ts","lineNumber":36,"sourceCode":"\treturn async (...args) => {\n\t\t// assume normal invocation at first\n\t\tconst [req, res, next, locals] = args;\n\t\t// short circuit if it is an error invocation\n\t\tif (req instanceof Error) {\n\t\t\tconst error = req;\n\t\t\tif (next) {\n\t\t\t\treturn next(error);\n\t\t\t} else {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\ttry {\n\t\t\tawait handler(req, res, next, locals);\n\t\t} catch (err) {\n\t\t\tlogger.error(`Could not render ${req.url}`);\n\t\t\tconsole.error(err);\n\t\t\tif (!res.headersSent) {\n\t\t\t\tres.writeHead(500, `Server error`);\n\t\t\t\tres.end();\n\t\t\t}\n\t\t}\n\t};\n}\n","sourceCodeStart":18,"sourceCodeEnd":42,"githubUrl":"https://github.com/withastro/astro/blob/52e6c34790cc8ac4e69e6135ace06049867e5c4a/packages/integrations/node/src/middleware.ts#L18-L42","documentation":"The @astrojs/node adapter wraps your built app so a Node HTTP server can serve it. When the underlying handler (page render, endpoint, or a handler you passed via middleware mode) throws or rejects, the wrapper logs `Could not render <url>` with the stack via console.error and, if headers are not yet sent, returns a bare `500 Server error`. It is the adapter's last-resort boundary; the body is empty because the app failed before it could render an error page. The real cause is the stack trace printed immediately above the response.","triggerScenarios":"Any uncaught exception during SSR in the Node build: undefined property access in a page, missing environment variable, failed database call inside an endpoint, throw inside `locals` population — while the response headers have not been sent yet.","commonSituations":"Running `node dist/server/entry.mjs` in production and seeing blank 500s; errors only visible in server stdout; env vars present in dev but absent in prod; errors thrown after streaming starts (headersSent) where the socket simply dies instead.","solutions":["Read the stack trace logged by console.error right above the 500 — it points at the exact page/endpoint line","Add an Astro middleware (src/middleware.ts) with try/catch that returns a styled 500 page so users never see the bare response","Verify production env vars, database URLs, and secrets are set before starting the server","If headersSent is true in logs, the page already streamed bytes — move the failing work earlier or stream defensively"],"exampleFix":"// before: page throws, users get bare '500 Server error'\nconst data = await db.query(`SELECT * FROM ${table}`);\n\n// after: src/middleware.ts catches render errors globally\nexport const onRequest = async (context, next) => {\n  try {\n    return await next();\n  } catch (err) {\n    context.logger.error(`Render failed: ${context.url}`, err);\n    return new Response('Server error', { status: 500 });\n  }\n};","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// src/middleware.ts — app-wide error boundary before the adapter's bare 500\nexport const onRequest = async (context, next) => {\n  try {\n    return await next();\n  } catch (err) {\n    context.logger.error(`Could not render ${context.url.pathname}`, err);\n    return context.rewrite('/500'); // or new Response(errorPage, { status: 500 })\n  }\n};","preventionTips":["Add an error-handling middleware so users get a branded 500 page instead of the bare adapter response","Fail fast on missing env vars/DB connections at server boot, not per-request","Run `node dist/server/entry.mjs` locally before deploying to catch render errors the dev server masks","Log url + stack (the adapter already does) and ship those logs to your monitoring"],"tags":["ssr","node-adapter","unhandled-exception","http-500"],"backgroundTag":"ssr-render-error","analyzedSha":"52e6c34790cc8ac4e69e6135ace06049867e5c4a","analyzedAt":"2026-08-18T18:48:03.901Z","contentChangedAt":"2026-08-18T18:48:03.901Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}