{"record":{"id":"e73e78f6d6c228f9","repo":"denoland/deno","slug":"return-value-from-onerror-handler-must-be-a-respon-e73e78","errorCode":null,"errorMessage":"Return value from onError handler must be a Response constructed via the Response constructor in this realm","messagePattern":"Return value from onError 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":780,"sourceCode":"        );\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);\n        if (!ObjectPrototypeIsPrototypeOf(ResponsePrototype, response)) {\n          throw new TypeError(\n            \"Return value from onError handler must be a response or a promise resolving to a response\",\n          );\n        }\n        inner = toInnerResponse(response);\n        if (inner === undefined) {\n          throw new TypeError(\n            \"Return value from onError handler must be a Response constructed via the Response constructor in this realm\",\n          );\n        }\n      } catch (error) {\n        if (otelState.METRICS_ENABLED) {\n          op_http_metric_handle_otel_error(req);\n        }\n        internals.log(\n          \"error\",\n          \"Exception in onError while handling exception\",\n          error,\n        );\n        response = internalServerError();\n        inner = toInnerResponse(response);\n      }\n    }\n\n    if (span) {","sourceCodeStart":762,"sourceCodeEnd":798,"githubUrl":"https://github.com/denoland/deno/blob/abd22074e47c6a5cd14e9e4e84743f084aa5a575/ext/http/00_serve.ts#L762-L798","documentation":"The onError path performs the same two-step validation as the main handler: first the prototype check, then toInnerResponse()/getInnerResponse() for the internal Deno slot. This TypeError means the Response returned by onError passed `instanceof Response` but carries no internal slot — it came from a subclass that skipped super(), or from another realm/polyfill (undici, node-fetch, a mock). Deno then logs 'Exception in onError while handling exception' and sends the built-in 500.","triggerScenarios":"onError returning a Response imported from undici/node-fetch, a Response subclass in the error path whose constructor never calls super(), or `Object.create(Response.prototype)` stubs used to fake error responses.","commonSituations":"Centralized error handlers in frameworks that import their own fetch polyfill, custom error-Response wrapper classes, test harnesses injecting fake Responses into onError.","solutions":["Build onError's return value with the global Response constructor","Call `super(init)` in any Response subclass used for error replies","Re-wrap foreign objects: `return new Response(foreign.body, foreign)`"],"exampleFix":"// before\nimport { Response as NodeFetchResponse } from 'node-fetch';\nonError: (e) => new NodeFetchResponse(e.message, { status: 500 }),\n\n// after\nonError: (e) => new Response(e.message, { status: 500 }), // global Response","handlingStrategy":"validation","validationCode":"// Normalize anything onError might return into a native Response:\nonError: (e) => {\n  const out = buildErrorPage(e); // possibly foreign\n  return out instanceof Response ? new Response(out.body, out) : new Response('Internal Server Error', { status: 500 });\n}","typeGuard":null,"tryCatchPattern":"// A second failure falls back to the built-in 500 automatically; log it:\n// 'Exception in onError while handling exception' appears in server logs — check there first\nDeno.serve({ handler, onError });","preventionTips":["Build error Responses with the global Response constructor","Do not import Response from polyfills anywhere in the error path","Call super() in Response subclasses used for error replies"],"tags":["http","deno-serve","on-error","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"}