{"record":{"id":"cd59de2e26d9ac1d","repo":"honojs/hono","slug":"env-has-to-include-the-2nd-argument-of-fetch-cd59de","errorCode":null,"errorMessage":"env has to include the 2nd argument of fetch.","messagePattern":"env has to include the 2nd argument of fetch\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/adapter/bun/websocket.ts","lineNumber":59,"sourceCode":"    protocol: ws.data.protocol,\n    close(code, reason) {\n      ws.close(code, reason)\n    },\n  })\n}\n\nexport const upgradeWebSocket: UpgradeWebSocket<any> = defineWebSocketHelper((c, events) => {\n  const server = getBunServer<{\n    upgrade<T>(\n      req: Request,\n      options?: {\n        data: T\n      }\n    ): boolean\n  }>(c)\n\n  if (!server) {\n    throw new TypeError('env has to include the 2nd argument of fetch.')\n  }\n  const upgradeResult = server.upgrade<BunWebSocketData>(c.req.raw, {\n    data: {\n      events,\n      url: new URL(c.req.url),\n      // The first requested subprotocol, exposed via WSContext.protocol to\n      // match the deno and cloudflare adapters.\n      protocol: c.req.header('sec-websocket-protocol')?.split(',')[0]?.trim() ?? '',\n    },\n  })\n  if (upgradeResult) {\n    return new Response(null)\n  }\n  return // failed\n})\n\nexport const websocket: BunWebSocketHandler<BunWebSocketData> = {\n  open(ws) {","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/honojs/hono/blob/e2740d5a1bd0b4254e517e3af8b60789284bc7bd/src/adapter/bun/websocket.ts#L41-L77","documentation":"The Bun WebSocket upgrade helper requires Bun's `Server` object (passed as the second argument to fetch() by Bun.serve) in order to call server.upgrade(). If the app is not mounted via `Bun.serve({ fetch: app.fetch })`, `c.env.server` is undefined and the WebSocket upgrade path cannot proceed.","triggerScenarios":"Using `upgradeWebSocket`/`createBunWebSocket` handlers on a Hono app that is not the direct fetch handler of Bun.serve — e.g. wrapped fetch that drops the server arg, running under Node, or calling app.request() in tests — then a WebSocket upgrade request arrives.","commonSituations":"Bun deployment where fetch is wrapped (e.g. for tracing/logging) without forwarding arguments; mixing Node WebSocket adapters with a Bun runtime or vice versa; integration tests that don't spin up a real Bun.serve.","solutions":["Use `Bun.serve({ fetch: app.fetch })` directly so Bun's server reaches c.env","Forward all args in wrappers: `fetch: (...args) => app.fetch(...args)`","Match the adapter to the runtime (use @hono/node-server WebSocket helper on Node)","For tests, run against a real Bun.serve instance or mock c.env.server with an upgrade() method"],"exampleFix":"// before\nBun.serve({ fetch: (req, _env) => app.fetch(req, _env) }) // env not a Bun Server\n\n// after\nBun.serve({ fetch: app.fetch, port: 3000 })","handlingStrategy":"validation","validationCode":"app.get('/ws', upgradeWebSocket(handler))\n\n// ensure mounting passes the server through:\nconst server = Bun.serve({ fetch: app.fetch, port: 3000 })","typeGuard":"const hasUpgradeableEnv = (env: unknown): env is { server: { upgrade(req: Request, opts: object): boolean } } =>\n  typeof (env as any)?.server?.upgrade === 'function'","tryCatchPattern":"try { return await upgradeWebSocket(handler)(c) } catch (e) { if (e instanceof Error && e.message === 'env has to include the 2nd argument of fetch.') return c.text('WebSocket unavailable', 501); throw e }","preventionTips":["Use Bun.serve({ fetch: app.fetch }) directly; avoid wrappers that drop the 2nd fetch arg","Pick the WS helper matching your runtime","Test WebSocket routes against a real server, not app.request()"],"tags":["bun","websocket","upgrade","adapter","env"],"backgroundTag":"websocket-upgrade-failed","analyzedSha":"e2740d5a1bd0b4254e517e3af8b60789284bc7bd","analyzedAt":"2026-08-28T10:18:08.750Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}