{"record":{"id":"adad9e1b4cb5607a","repo":"oven-sh/bun","slug":"fetch-did-not-return-a-response","errorCode":null,"errorMessage":"fetch() did not return a Response","messagePattern":"fetch\\(\\) did not return a Response","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/bun-lambda/runtime.ts","lineNumber":613,"sourceCode":"        ? options.port\n        : typeof options.port === \"string\"\n          ? parseInt(options.port)\n          : this.port;\n    this.hostname = options.hostname ?? this.hostname;\n    this.development = options.development ?? this.development;\n  }\n\n  async fetch(request: Request): Promise<Response> {\n    this.pendingRequests++;\n    try {\n      let response = await this.#lambda.fetch(request, this);\n      if (response instanceof Response) {\n        return response;\n      }\n      if (response === undefined && this.#upgrade !== null) {\n        return this.#upgrade;\n      }\n      throw new Error(\"fetch() did not return a Response\");\n    } catch (cause) {\n      console.error(cause);\n      if (this.#lambda.error !== undefined) {\n        try {\n          return await this.#lambda.error(cause);\n        } catch (cause) {\n          console.error(cause);\n        }\n      }\n      return new Response(null, { status: 500 });\n    } finally {\n      this.pendingRequests--;\n      this.#upgrade = null;\n    }\n  }\n\n  upgrade<T = undefined>(\n    request: Request,","sourceCodeStart":595,"sourceCodeEnd":631,"githubUrl":"https://github.com/oven-sh/bun/blob/8c5296ac459e8252d3cd702f3fbcbb0c249d95d5/packages/bun-lambda/runtime.ts#L595-L631","documentation":"The bun-lambda runtime invokes your exported fetch(request) handler and requires the resolved value to be a genuine Response instance; undefined is only tolerated when a WebSocket upgrade was performed (the runtime substitutes its stored upgrade response). Anything else — undefined with no upgrade, null, a plain object, or a Response-like from a duplicate Response class — throws. The runtime catches it, logs via console.error, optionally calls your exported error(cause) handler, and returns a 500 Response.","triggerScenarios":"A handler branch that falls through without returning; returning a serialized or plain-object response; returning undefined on a non-WebSocket route; instanceof Response failing because the handler constructs Responses from a second bundled copy of the runtime types.","commonSituations":"Porting Bun.serve/Cloudflare-style workers to bun-lambda and forgetting the default return; early-return refactors that drop the Response; bundlers that duplicate polyfills making cross-realm Response objects fail instanceof.","solutions":["Make every code path in fetch return a Response (add a final 'return new Response(...)' as the default)","Return undefined only on the WebSocket upgrade path (export websocket handlers and let the runtime own the upgrade)","Add an exported error handler as a safety net so failures render a controlled page instead of a bare 500","Ensure a single copy of the runtime/types is bundled so instanceof Response holds"],"exampleFix":"// before\nexport default {\n  async fetch(request) {\n    if (request.method === 'GET') return new Response('hi');\n    // falls through -> \"fetch() did not return a Response\" + 500\n  },\n};\n\n// after\nexport default {\n  async fetch(request) {\n    if (request.method === 'GET') return new Response('hi');\n    return new Response('Method Not Allowed', { status: 405 });\n  },\n};","handlingStrategy":"type-guard","validationCode":"const isResponse = (v: unknown): v is Response => v instanceof Response;\n\nconst raw = await handler.fetch(request);\nif (!isResponse(raw)) throw new TypeError('handler must return a Response');","typeGuard":"const isResponse = (v: unknown): v is Response =>\n  v instanceof Response || (!!v && typeof (v as Response).body !== 'undefined' && typeof (v as Response).status === 'number');","tryCatchPattern":"try {\n  return await lambda.fetch(request);\n} catch (cause) {\n  console.error(cause);\n  return lambda.error ? await lambda.error(cause) : new Response(null, { status: 500 });\n}","preventionTips":["End every fetch handler with a default 'return new Response(...)'","Export an error handler so unexpected failures render a controlled response","Return undefined only on the WebSocket upgrade path","Avoid bundling duplicate runtime copies that break instanceof Response"],"tags":["lambda","fetch","response","serverless"],"backgroundTag":null,"analyzedSha":"8c5296ac459e8252d3cd702f3fbcbb0c249d95d5","analyzedAt":"2026-08-16T08:01:58.794Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}