withastro/astro · error
Incomplete request
Error message
Incomplete request
What it means
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.
Source
Thrown at packages/astro/src/vite-plugin-astro-server/plugin.ts:144
route: '',
handle: trailingSlashMiddleware(settings),
});
// Prevent serving files outside srcDir/publicDir (e.g., /README.md at project root)
viteServer.middlewares.stack.unshift({
route: '',
handle: routeGuardMiddleware(settings),
});
// Validate Sec-Fetch metadata headers to restrict cross-origin subresource requests
viteServer.middlewares.stack.unshift({
route: '',
handle: secFetchMiddleware(logger, settings.config.security?.allowedDomains),
});
if (prerenderHandler && shouldHandlePrerenderInCore) {
viteServer.middlewares.use(
async function astroDevPrerenderHandler(request, response, next) {
if (request.url === undefined || !request.method) {
response.writeHead(500, 'Incomplete request');
response.end();
return;
}
if (request.url.startsWith('/@') || request.url.startsWith('/__')) {
return next();
}
if (request.url.includes('/node_modules/')) {
return next();
}
try {
const pathname = decodeURI(new URL(request.url, 'http://localhost').pathname);
const { routes } = (await prerenderHandler.environment.runner.import(
'virtual:astro:routes',
)) as { routes: RouteInfo[] };
const routesList = { routes: routes.map((route) => route.routeData) };View on GitHub (pinned to 52e6c34790)
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
Example fix
// Triggers the guard (raw socket, no request line) // $ printf 'GARBAGE\r\n\r\n' | nc localhost 4321 -> 500 Incomplete request // Never triggers it // $ curl -i http://localhost:4321/
Defensive patterns
Strategy: validation
Validate before calling
// Only for tooling that drives the dev-server middleware stack directly
import type { IncomingMessage } from 'node:http';
function isCompleteRequest(req: Partial<IncomingMessage>): boolean {
return typeof req.url === 'string' && typeof req.method === 'string' && req.method.length > 0;
}
if (!isCompleteRequest(mockReq)) throw new Error('refusing to forward incomplete request'); Type guard
type CompleteRequest = IncomingMessage & { url: string; method: string };
function isCompleteRequest(req: unknown): req is CompleteRequest {
const r = req as Partial<IncomingMessage>;
return typeof r?.url === 'string' && typeof r?.method === 'string' && r.method.length > 0;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- No cached compile metadata found for "${id}". The main Astro
- Unable to find CSS for ${routeData.component}. This is likel
- UnknownContentCollectionError
- ▶ vite.server.fs.strict has been disabled! Files on your m
- [RSS] You can only glob entries within 'src/pages/' when pas
AI-assisted analysis of withastro/astro@52e6c34790 (2026-08-18).
Data as JSON: /api/errors/be624e222c803499.
Report an issue: GitHub.