{"record":{"id":"be624e222c803499","repo":"withastro/astro","slug":"incomplete-request","errorCode":null,"errorMessage":"Incomplete request","messagePattern":"Incomplete request","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"packages/astro/src/vite-plugin-astro-server/plugin.ts","lineNumber":144,"sourceCode":"\t\t\t\t\troute: '',\n\t\t\t\t\thandle: trailingSlashMiddleware(settings),\n\t\t\t\t});\n\t\t\t\t// Prevent serving files outside srcDir/publicDir (e.g., /README.md at project root)\n\t\t\t\tviteServer.middlewares.stack.unshift({\n\t\t\t\t\troute: '',\n\t\t\t\t\thandle: routeGuardMiddleware(settings),\n\t\t\t\t});\n\t\t\t\t// Validate Sec-Fetch metadata headers to restrict cross-origin subresource requests\n\t\t\t\tviteServer.middlewares.stack.unshift({\n\t\t\t\t\troute: '',\n\t\t\t\t\thandle: secFetchMiddleware(logger, settings.config.security?.allowedDomains),\n\t\t\t\t});\n\n\t\t\t\tif (prerenderHandler && shouldHandlePrerenderInCore) {\n\t\t\t\t\tviteServer.middlewares.use(\n\t\t\t\t\t\tasync function astroDevPrerenderHandler(request, response, next) {\n\t\t\t\t\t\t\tif (request.url === undefined || !request.method) {\n\t\t\t\t\t\t\t\tresponse.writeHead(500, 'Incomplete request');\n\t\t\t\t\t\t\t\tresponse.end();\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (request.url.startsWith('/@') || request.url.startsWith('/__')) {\n\t\t\t\t\t\t\t\treturn next();\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (request.url.includes('/node_modules/')) {\n\t\t\t\t\t\t\t\treturn next();\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tconst pathname = decodeURI(new URL(request.url, 'http://localhost').pathname);\n\t\t\t\t\t\t\t\tconst { routes } = (await prerenderHandler.environment.runner.import(\n\t\t\t\t\t\t\t\t\t'virtual:astro:routes',\n\t\t\t\t\t\t\t\t)) as { routes: RouteInfo[] };\n\t\t\t\t\t\t\t\tconst routesList = { routes: routes.map((route) => route.routeData) };","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/withastro/astro/blob/52e6c34790cc8ac4e69e6135ace06049867e5c4a/packages/astro/src/vite-plugin-astro-server/plugin.ts#L126-L162","documentation":"During `astro dev`, requests first pass through `astroDevPrerenderHandler`, the middleware that renders prerendered routes inside the core dev server. It immediately rejects any request whose `url` is undefined or whose `method` is missing by writing a bare 500 with reason 'Incomplete request'. Node's HTTP parser always populates these fields for well-formed requests, so hitting this guard means the dev server received a degenerate or programmatically forged request rather than a valid HTTP message.","triggerScenarios":"A raw TCP client connects to the dev port and sends bytes that never form a valid HTTP request line; a proxy, test harness, or script invokes the Vite middleware stack with a mock req object lacking `url`/`method`; load-balancer or port-scanner probes open connections without speaking HTTP.","commonSituations":"Corporate health checks or vulnerability scanners probing the dev port; custom dev tooling that drives `viteServer.middlewares` directly; hand-rolled socket scripts instead of fetch/curl; upgrading Astro to a version where prerender handling moved into core and this guard appeared.","solutions":["Confirm with a real request: `curl -i http://localhost:4321/` — a well-formed request must never return 'Incomplete request'; if it does, a middleman is mangling it","Identify the client producing malformed traffic on the dev port (probes, scripts, proxies) and stop or fix it","If you inject middleware or drive the stack programmatically, always pass full http.IncomingMessage-shaped objects with `url` and `method` set","Check custom middleware ordering if you mutate `req` before Astro's handlers run"],"exampleFix":"// Triggers the guard (raw socket, no request line)\n// $ printf 'GARBAGE\\r\\n\\r\\n' | nc localhost 4321  -> 500 Incomplete request\n\n// Never triggers it\n// $ curl -i http://localhost:4321/","handlingStrategy":"validation","validationCode":"// Only for tooling that drives the dev-server middleware stack directly\nimport type { IncomingMessage } from 'node:http';\nfunction isCompleteRequest(req: Partial<IncomingMessage>): boolean {\n  return typeof req.url === 'string' && typeof req.method === 'string' && req.method.length > 0;\n}\nif (!isCompleteRequest(mockReq)) throw new Error('refusing to forward incomplete request');","typeGuard":"type CompleteRequest = IncomingMessage & { url: string; method: string };\nfunction isCompleteRequest(req: unknown): req is CompleteRequest {\n  const r = req as Partial<IncomingMessage>;\n  return typeof r?.url === 'string' && typeof r?.method === 'string' && r.method.length > 0;\n}","tryCatchPattern":null,"preventionTips":["Always talk to the dev server with a real HTTP client (fetch, curl, browser) — never raw sockets","Keep any proxy in front of `astro dev` transparent: forward method and full URL unchanged","Ignore isolated 500 'Incomplete request' lines from scanners; correlate them with the offending client IP in logs"],"tags":["dev-server","http","middleware","vite"],"backgroundTag":"malformed-http-request","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"}