{"record":{"id":"04bde810e2a261ae","repo":"denoland/deno","slug":"return-value-from-onerror-handler-must-be-a-respon","errorCode":null,"errorMessage":"Return value from onError handler must be a response or a promise resolving to a response","messagePattern":"Return value from onError handler must be a response or a promise resolving to a response","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/http/00_serve.ts","lineNumber":755,"sourceCode":"        );\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);\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        );","sourceCodeStart":737,"sourceCodeEnd":773,"githubUrl":"https://github.com/denoland/deno/blob/89f33cbef296a2b287f323d42de54c871fa69c77/ext/http/00_serve.ts#L737-L773","documentation":"When a serve handler throws, Deno calls the configured onError callback and expects it (or its promise) to resolve to a Response to send instead. If onError returns a non-Response, serve throws this TypeError; the fallback then logs 'Exception in onError while handling exception' and closes the request with a 500.","triggerScenarios":"onError returning a string like `Error: ${message}`; onError that forgets a return on some branch; onError returning the caught error object itself; onError that returns undefined after logging.","commonSituations":"Converting an Express-style error middleware that replied with res.send(text); adding logging-first onError handlers without a return value.","solutions":["Make onError return a Response: new Response(message, { status: 500 })","Cover every branch of onError, including its own catch/finally paths","Keep using throw inside handlers; reserve onError for shaping the error page"],"exampleFix":"// before\nDeno.serve({\n  onError: (e) => `Error: ${e.message}`, // string, not a Response\n  handler,\n});\n\n// after\nDeno.serve({\n  onError: (e) => new Response(`Error: ${e.message}`, { status: 500 }),\n  handler,\n});","handlingStrategy":"type-guard","validationCode":"// Ensure onError always yields a Response\nconst safeOnError = async (err) => {\n  const r = await onError?.(err);\n  return r instanceof Response ? r : new Response(\"Internal Server Error\", { status: 500 });\n};","typeGuard":"function isValidOnErrorResult(v) {\n  return v instanceof Response;\n}","tryCatchPattern":"// serve already wraps a failing onError with a 500 and logs\n// 'Exception in onError while handling exception'; keep onError trivial and total:\nconst onError = (err) => new Response(`Error: ${err.message}`, { status: 500 });","preventionTips":["Keep onError synchronous and always returning new Response(...)","Do not forward third-party Response types out of onError","Return a plain 500 on any unexpected shape instead of the raw value"],"tags":["http","serve","on-error","handler"],"backgroundTag":null,"analyzedSha":"89f33cbef296a2b287f323d42de54c871fa69c77","analyzedAt":"2026-08-16T07:54:21.310Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}