denoland/deno · error · TypeError

First argument to 'respondWith' must be a Response construct

Error message

First argument to 'respondWith' must be a Response constructed via the Response constructor in this realm

What it means

A second, stricter guard after the prototype check: toInnerResponse(resp) must return an inner response, i.e. the object must carry Deno's internal Response slot, which only objects built by this realm's Response constructor have. Objects that fake it (Object.create(Response.prototype), Response subclasses instantiated in another realm/worker, or polyfilled Responses) pass the prototype test but lack the internal slot and are rejected here instead of crashing on innerResp.body.

Source

Thrown at ext/http/01_http.js:213

  writeStreamRid,
) {
  return async function respondWith(resp) {
    try {
      resp = await resp;
      if (!(ObjectPrototypeIsPrototypeOf(ResponsePrototype, resp))) {
        throw new TypeError(
          "First argument to 'respondWith' must be a Response or a promise resolving to a Response",
        );
      }

      // The Response prototype check above passes for Response-like objects
      // that don't carry the internal slot (e.g. `Object.create(Response.prototype)`
      // or a polyfilled/foreign-realm Response). Reject those here instead of
      // crashing later on `innerResp.body`. Mirrors the Deno.serve guard
      // added in #34416.
      const innerResp = toInnerResponse(resp);
      if (innerResp === undefined) {
        throw new TypeError(
          "First argument to 'respondWith' must be a Response constructed via the Response constructor in this realm",
        );
      }

      // If response body length is known, it will be sent synchronously in a
      // single op, in other case a "response body" resource will be created and
      // we'll be streaming it.
      /** @type {ReadableStream<Uint8Array> | Uint8Array | null} */
      let respBody = null;
      if (innerResp.body !== null) {
        if (innerResp.body.unusable()) {
          throw new TypeError("Body is unusable");
        }
        if (
          ObjectPrototypeIsPrototypeOf(
            ReadableStreamPrototype,
            innerResp.body.streamOrStatic,
          )

View on GitHub (pinned to 89f33cbef2)

Solutions

  1. Construct the response in the same realm with the real constructor: new Response(body, init).
  2. When receiving a value from another realm, rebuild it: httpConn.respondWith(new Response(await foreignResp.body, foreignResp)).
  3. Remove polyfills/shims for Response from the serving path (don't polyfill built-ins when running under Deno).

Example fix

// before
const fake = Object.create(Response.prototype);
fake.status = 200;
httpConn.respondWith(fake);

// after
httpConn.respondWith(new Response("ok"));
Defensive patterns

Strategy: validation

Validate before calling

function isRealmResponse(v: unknown): boolean {
  if (!(v instanceof Response)) return false;
  try { return Object.getOwnPropertySymbols(v).length > 0 || new Response(v.body, v).body !== undefined || true; } catch { return false; }
}

Type guard

function isRealResponse(v: unknown): v is Response { try { return v instanceof Response && !(Symbol.for("deno.inner") in (v as object) && (v as any)[Symbol.for("deno.inner")] === undefined); } catch { return false; } }

Try / catch

try { await httpConn.respondWith(resp); } catch (e) { if (e instanceof TypeError && e.message.includes("in this realm")) { await httpConn.respondWith(new Response(null, { status: resp.status ?? 200, headers: resp.headers })); return; } throw e; }

Prevention

When it happens

Trigger: Object.create(Response.prototype) passed to respondWith; a Response created inside a Worker or vm-like realm and shipped to the main thread; a Response polyfill whose instances share Response.prototype but never went through the constructor; cloned structurally via property copying.

Common situations: Cross-realm code (node compat shims, sandboxed evaluators, import maps pulling a fetch polyfill); libraries that wrap/subclass Response from a different Deno instance; defensive Object.create tricks to avoid constructor validation.

Related errors


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