denoland/deno · error · TypeError
Return value from serve handler must be a Response construct
Error message
Return value from serve handler must be a Response constructed via the Response constructor in this realm
What it means
The prototype check in serve passes for Response-like objects that lack the internal slot only real Responses carry: instances from another realm or polyfill, or a subclass whose constructor skipped super(). getInnerResponse returns undefined for such objects and serve rejects them with this clear error instead of crashing later while reading the internal slot.
Source
Thrown at ext/http/00_serve.ts:735
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())",
);
}
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);View on GitHub (pinned to 89f33cbef2)
Solutions
- Re-create the response at the boundary with the realm's constructor: return new Response(foreign.body, { status: foreign.status, headers: foreign.headers })
- If the foreign body is not a usable stream, buffer it first: new Response(await foreign.text(), ...)
- In Response subclasses, always call super(...) so the internal slot is installed
- Pass serialized data across realm boundaries instead of Response objects
Example fix
// before
import { fetch as undiciFetch } from "npm:undici";
Deno.serve(async () => {
const r = await undiciFetch("https://example.com");
return r; // undici Response: no Deno internal slot
});
// after
import { fetch as undiciFetch } from "npm:undici";
Deno.serve(async () => {
const r = await undiciFetch("https://example.com");
return new Response(r.body, { status: r.status, headers: r.headers });
}); Defensive patterns
Strategy: type-guard
Validate before calling
// Re-wrap anything that might be cross-realm before returning
function toRealmResponse(v) {
if (v instanceof Response && Object.getPrototypeOf(v) === Response.prototype) {
return v;
}
if (v instanceof Response) {
return new Response(v.body, { status: v.status, headers: v.headers });
}
return new Response(String(v));
} Type guard
// Heuristic: accepts direct instances of THIS realm's Response;
// valid subclasses should call super() and be re-wrapped at the boundary anyway
function isRealmResponse(v) {
return v instanceof Response && v.constructor === Response;
} Try / catch
Deno.serve({
onError: (err) => new Response("Internal Server Error", { status: 500 }),
handler: async (req) => {
try {
return await route(req);
} catch (err) {
if (err instanceof TypeError && err.message.includes("in this realm")) {
return new Response("Cross-realm response rejected", { status: 500 });
}
throw err;
}
},
}); Prevention
- Never forward Response objects from npm packages (undici) or other Workers; re-create them with the built-in Response
- Always call super(...) in Response subclasses
- Pass plain data across realm boundaries and build the Response where you serve it
When it happens
Trigger: Returning a Response obtained from npm packages that bundle their own implementation (e.g. undici), a Response created inside a Worker/vm context, an object that merely subclasses Response without calling super(), or an object forged with Object.create(Response.prototype).
Common situations: Using npm HTTP clients or SDKs in Deno and forwarding their Response directly; SSR/framework code that routes through polyfills; Response subclasses written as `class R extends Response { constructor() { return {} as any; } }`.
Related errors
- Return value from onError handler must be a Response constru
- Return value from serve handler must be a response or a prom
- Return value from serve handler must not be an error respons
- The body of the Response returned from the serve handler has
- Already upgraded
AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16).
Data as JSON: /api/errors/e6b18143d9fb8144.
Report an issue: GitHub.