denoland/deno · error · TypeError
Return value from serve handler must be a response or a prom
Error message
Return value from serve handler must be a response or a promise resolving to a response
What it means
Deno.serve requires the handler (or the promise it returns) to resolve to an instance of the built-in Response. Before sending, serve validates the value's prototype chain; anything else (string, plain object, undefined) throws this TypeError so the failure surfaces in the handler's context instead of crashing the native layer. The throw is routed to onError, which by default produces a 500 response.
Source
Thrown at ext/http/00_serve.ts:724
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 89f33cbef2)
Solutions
- Wrap non-Response values: return new Response('ok') or return Response.json(data)
- Audit every branch of the handler, including catch blocks, so each path returns a Response
- In middleware chains, always return the downstream handler's result
- Type the handler as (req: Request) => Response | Promise<Response> so mismatches surface at compile time
Example fix
// before
Deno.serve((req) => {
if (req.url.endsWith("/health")) return "ok"; // plain string
return appHandler(req);
});
// after
Deno.serve((req) => {
if (req.url.endsWith("/health")) return new Response("ok");
return appHandler(req);
}); Defensive patterns
Strategy: type-guard
Validate before calling
// Validate before returning from any handler path
if (!(response instanceof Response)) {
response = new Response(String(response));
}
return response; Type guard
function isResponse(v) {
return v instanceof Response;
} Try / catch
Deno.serve({
onError: (err) =>
err instanceof TypeError &&
err.message.includes("must be a response or a promise")
? new Response("Handler must return a Response", { status: 500 })
: new Response("Internal Server Error", { status: 500 }),
handler,
}); Prevention
- Type handlers as (req: Request) => Response | Promise<Response>
- Return Response.json(data) instead of raw objects
- Check every guard clause and catch block for a missing Response return
When it happens
Trigger: Returning 'ok', a parsed JSON object (await res.json()), or a URL from the handler; a code path that falls off the end without a return statement; a middleware branch that forgets 'return next(request)'.
Common situations: Porting Express-style handlers that used res.send(...); early-return guard clauses with a missing return; returning the result of a fetch().json() call instead of the fetch Response itself.
Related errors
- Return value from serve handler must not be an error respons
- Return value from serve handler must be a Response construct
- The body of the Response returned from the serve handler has
- Return value from onError handler must be a response or a pr
- Already upgraded
AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16).
Data as JSON: /api/errors/b41ecb8ad95ce0ec.
Report an issue: GitHub.