{"record":{"id":"e6b18143d9fb8144","repo":"denoland/deno","slug":"return-value-from-serve-handler-must-be-a-response-e6b181","errorCode":null,"errorMessage":"Return value from serve handler must be a Response constructed via the Response constructor in this realm","messagePattern":"Return value from serve handler must be a Response constructed via the Response constructor in this realm","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/http/00_serve.ts","lineNumber":754,"sourceCode":"          request,\n          new ServeHandlerInfo(innerRequest),\n        );\n      }\n\n      // Throwing Error if the handler return value is not a Response class\n      if (!ObjectPrototypeIsPrototypeOf(ResponsePrototype, response)) {\n        throw new TypeError(\n          \"Return value from serve handler must be a response or a promise resolving to a response\",\n        );\n      }\n\n      // The Response prototype check above passes for Response-like objects\n      // (e.g. a subclass that skipped super(), or a Response from a different\n      // realm/polyfill). Those don't carry the internal slot we read from\n      // below, so reject them with a clear error instead of crashing later.\n      inner = getInnerResponse(response);\n      if (inner === undefined) {\n        throw new TypeError(\n          \"Return value from serve handler must be a Response constructed via the Response constructor in this realm\",\n        );\n      }\n\n      if (inner.type === \"error\") {\n        throw new TypeError(\n          \"Return value from serve handler must not be an error response (like Response.error())\",\n        );\n      }\n\n      if (responseBodyUsed(response)) {\n        throw new TypeError(\n          \"The body of the Response returned from the serve handler has already been consumed\",\n        );\n      }\n    } catch (error) {\n      try {\n        response = await onError(error);","sourceCodeStart":736,"sourceCodeEnd":772,"githubUrl":"https://github.com/denoland/deno/blob/abd22074e47c6a5cd14e9e4e84743f084aa5a575/ext/http/00_serve.ts#L736-L772","documentation":"After the prototype check passes, Deno.serve reads the internal Deno response slot with getInnerResponse(). A value that looks like a Response (shares the prototype) but lacks that internal slot triggers this TypeError. Typical sources: a subclass that never called super(), or a Response object created by a different realm/polyfill (undici, node-fetch, a mock) that merely mimics the prototype chain.","triggerScenarios":"`class MyResponse extends Response` whose constructor skips `super(...)` and only sets fields, returning a Response produced by an npm dependency that ships its own fetch implementation, or a stub object created with `Object.create(Response.prototype)` in tests.","commonSituations":"Custom Response subclasses adding metadata fields, framework middlewares that wrap or replace the Response with a polyfilled one, test doubles leaking into a running server, bundlers aliasing Response to a polyfill.","solutions":["Always call `super(init)` in Response subclasses before setting extra fields","Do not import or return Response instances from undici/node-fetch/polyfills; use the global Response","Re-wrap foreign instances: `return new Response(foreign.body, foreign)`","In tests, build stubs with the real constructor instead of Object.create(Response.prototype)"],"exampleFix":"// before\nclass TeeShirt extends Response {\n  constructor(size) {\n    this.size = size; // no super() -> no internal slot\n  }\n}\n\n// after\nclass TeeShirt extends Response {\n  size;\n  constructor(size) {\n    super(`size=${size}`); // internal slot created\n    this.size = size;\n  }\n}","handlingStrategy":"validation","validationCode":"// Re-wrap anything that might not carry the Deno internal slot:\nlet out = await callback(req, info);\nif (!(out instanceof Response) || Object.getPrototypeOf(out) === null) {\n  out = new Response(out.body, out);\n}\nreturn out;","typeGuard":null,"tryCatchPattern":"// The internal slot is not observable from JS; rely on onError to convert this to a 500\nDeno.serve({ handler, onError: () => new Response('Internal Server Error', { status: 500 }) });","preventionTips":["Never import Response from undici/node-fetch or accept one from a dependency as a return value","Always call super(init) in Response subclasses","Build test doubles with the real constructor, not Object.create(Response.prototype)"],"tags":["http","deno-serve","response","subclassing","cross-realm","polyfill"],"backgroundTag":"cross-realm-instanceof","analyzedSha":"abd22074e47c6a5cd14e9e4e84743f084aa5a575","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}