denoland/deno · error · TypeError
Return value from serve handler must not be an error…
Error message
Return value from serve handler must not be an error response (like Response.error())
What it means
Deno.serve rejects handler return values whose internal type is 'error', which is the state produced by `Response.error()`. Response.error() is a fetch-API marker meaning 'network error, no HTTP response exists' — it has no status, no headers, and nothing to put on the wire, so it cannot be served. The throw goes to onError and becomes a 500 if unhandled.
Solutions
- Throw an Error from the handler instead; Deno.serve routes it to onError which returns a 500
- When proxying fetch, check `upstream.type === 'error'` and map it to a real status: `new Response('Bad Gateway', { status: 502 })`
- Configure onError to produce the exact failure response you want
Example fix
// before
Deno.serve(async (req) => {
const upstream = await fetch(target, req);
return upstream; // fetch network failure resolves to Response.error()
});
// after
Deno.serve(async (req) => {
try {
const upstream = await fetch(target, req);
if (upstream.type === 'error') throw new Error('upstream unreachable');
return upstream;
} catch {
return new Response('Bad Gateway', { status: 502 });
}
}); Defensive patterns
Strategy: validation
Validate before calling
// Check the public type before returning a possibly-error Response:
if (response.type === 'error') {
response = new Response('Bad Gateway', { status: 502 });
}
return response; Type guard
const isErrorResponse = (r: Response): boolean => r.type === 'error';
Try / catch
// Prefer throwing; onError owns the wire format:
if (badUpstream) throw new Error('upstream unreachable');
// onError: (e) => new Response('Internal Server Error', { status: 500 }) Prevention
- Treat Response.error() as a client-fetch concept; never return it from a server
- When proxying fetch, always inspect r.type === 'error' before forwarding
- Use onError for failure responses instead of error-marker objects
When it happens
Trigger: `return Response.error()` used as an error signal in a handler, code that proxies upstream fetches and forwards the upstream Response object without checking whether the fetch failed (a failed fetch resolves to Response.error() rather than throwing), or generic `catch` blocks returning Response.error().
Common situations: Reverse proxies forwarding `await fetch(upstream)` results verbatim, developers coming from client-side fetch where Response.error() is a familiar pattern, error handlers that want to 'signal failure' to the server runtime.
Related errors
- Both 'cert' and 'key' must be provided to enable HTTPS
- Cannot serve HTTP requests: either a `handler` or `options`…
- Cannot serve HTTP requests: handler must be a function…
- ERR_INVALID_URL
- ERR_PROXY_INVALID_CONFIG
AI-assisted analysis of denoland/deno@abd22074e4 (2026-08-20).
Data as JSON: /api/errors/8c8e47a07c51a39a.
Report an issue: GitHub.
Appendix: source
Thrown at ext/http/00_serve.ts:760
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())",
);
}
if (responseBodyUsed(response)) {
throw new TypeError(
"The body of the Response returned from the serve handler has already been consumed",
);
}
} catch (error) {
try {
response = await onError(error);
if (!ObjectPrototypeIsPrototypeOf(ResponsePrototype, response)) {
throw new TypeError(
"Return value from onError handler must be a response or a promise resolving to a response",
);
}
inner = toInnerResponse(response);View on GitHub (pinned to abd22074e4)