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

  1. Re-create the response at the boundary with the realm's constructor: return new Response(foreign.body, { status: foreign.status, headers: foreign.headers })
  2. If the foreign body is not a usable stream, buffer it first: new Response(await foreign.text(), ...)
  3. In Response subclasses, always call super(...) so the internal slot is installed
  4. 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

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


AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16). Data as JSON: /api/errors/e6b18143d9fb8144. Report an issue: GitHub.