denoland/deno · error · TypeError
Return value from serve handler must be a response or a…
Error message
Return value from serve handler must be a response or a promise resolving to a response
What it means
Deno.serve validates that the handler's settled return value is a real Response before sending anything. This TypeError fires when the value is not even on the Response prototype chain — a plain object, string, undefined, or null. The throw is caught by the surrounding try/catch and passed to onError, which defaults to a 500 response.
Solutions
- Make every code path return a Response: use `new Response(...)`, `Response.json(...)`, or `Response.redirect(...)`
- Add a fallback at the end of the handler: `return response ?? new Response('Not Found', { status: 404 })`
- Type the handler as `(req: Request) => Response | Promise<Response>` so the compiler flags missing returns
- Let thrown errors go to onError instead of returning error-shaped plain objects
Example fix
// before
Deno.serve(async (req) => {
if (!req.headers.get('authorization')) return; // undefined
return { status: 200, body: 'ok' }; // plain object
});
// after
Deno.serve(async (req) => {
if (!req.headers.get('authorization')) {
return new Response('Unauthorized', { status: 401 });
}
return Response.json({ ok: true });
}); Defensive patterns
Strategy: type-guard
Validate before calling
// Guarantee every path yields a Response before it reaches Deno.serve:
const handler = async (req: Request): Promise<Response> => {
const data = await compute(req);
return Response.json(data ?? null); // no path returns undefined
}; Type guard
const isResponse = (v: unknown): v is Response => v instanceof Response;
Try / catch
// Centralized safety net via onError (receives this TypeError as-is):
Deno.serve({
handler,
onError: (e) => {
console.error(e);
return new Response('Internal Server Error', { status: 500 });
},
}); Prevention
- Type handlers as (req: Request) => Response | Promise<Response> so TS flags missing returns
- Enable noImplicitReturns to catch branches that fall through
- End handlers with an explicit fallback: return response ?? new Response('Not Found', { status: 404 })
When it happens
Trigger: An async handler with a code path that has no return statement (resolves undefined), returning raw JSON data (`return { ok: true }`), returning a string body directly, or forgetting to return the Response from an inner helper (`await next()` style middleware that drops the value).
Common situations: Porting Express-style handlers that returned plain objects or used res.json(), early-return guards (`if (!auth) return;`), refactors that renamed the response variable but left `return;` behind.
Related errors
- Return value from onError handler must be a response or a…
- Cannot serve HTTP requests: either a `handler` or `options`…
- Cannot serve HTTP requests: handler must be a function…
- Both 'cert' and 'key' must be provided to enable HTTPS
- ERR_HTTP_INVALID_HEADER_VALUE
AI-assisted analysis of denoland/deno@abd22074e4 (2026-08-20).
Data as JSON: /api/errors/b41ecb8ad95ce0ec.
Report an issue: GitHub.
Appendix: source
Thrown at ext/http/00_serve.ts:743
response = await callback();
} else {
innerRequest = new InnerRequest(req, context);
const request = fromInnerRequest(innerRequest, "immutable");
innerRequest.request = request;
if (span) {
updateSpanFromRequest(span, request);
}
response = await callback(
request,
new ServeHandlerInfo(innerRequest),
);
}
// Throwing Error if the handler return value is not a Response class
if (!ObjectPrototypeIsPrototypeOf(ResponsePrototype, response)) {
throw new TypeError(
"Return value from serve handler must be a response or a promise resolving to a response",
);
}
// The Response prototype check above passes for Response-like objects
// (e.g. a subclass that skipped super(), or a Response from a different
// realm/polyfill). Those don't carry the internal slot we read from
// below, so reject them with a clear error instead of crashing later.
inner = getInnerResponse(response);
if (inner === undefined) {
throw new TypeError(
"Return value from serve handler must be a Response constructed via the Response constructor in this realm",
);
}
if (inner.type === "error") {
throw new TypeError(
"Return value from serve handler must not be an error response (like Response.error())",View on GitHub (pinned to abd22074e4)