honojs/hono · error · TypeError
env has to include the 2nd argument of fetch.
Error message
env has to include the 2nd argument of fetch.
What it means
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.
Source
Thrown at src/adapter/bun/websocket.ts:59
protocol: ws.data.protocol,
close(code, reason) {
ws.close(code, reason)
},
})
}
export const upgradeWebSocket: UpgradeWebSocket<any> = defineWebSocketHelper((c, events) => {
const server = getBunServer<{
upgrade<T>(
req: Request,
options?: {
data: T
}
): boolean
}>(c)
if (!server) {
throw new TypeError('env has to include the 2nd argument of fetch.')
}
const upgradeResult = server.upgrade<BunWebSocketData>(c.req.raw, {
data: {
events,
url: new URL(c.req.url),
// The first requested subprotocol, exposed via WSContext.protocol to
// match the deno and cloudflare adapters.
protocol: c.req.header('sec-websocket-protocol')?.split(',')[0]?.trim() ?? '',
},
})
if (upgradeResult) {
return new Response(null)
}
return // failed
})
export const websocket: BunWebSocketHandler<BunWebSocketData> = {
open(ws) {View on GitHub (pinned to e2740d5a1b)
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
Example fix
// before
Bun.serve({ fetch: (req, _env) => app.fetch(req, _env) }) // env not a Bun Server
// after
Bun.serve({ fetch: app.fetch, port: 3000 }) Defensive patterns
Strategy: validation
Validate before calling
app.get('/ws', upgradeWebSocket(handler))
// ensure mounting passes the server through:
const server = Bun.serve({ fetch: app.fetch, port: 3000 }) Type guard
const hasUpgradeableEnv = (env: unknown): env is { server: { upgrade(req: Request, opts: object): boolean } } =>
typeof (env as any)?.server?.upgrade === 'function' Try / catch
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 } Prevention
- 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()
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Failed to upgrade WebSocket
- env has to include the 2nd argument of fetch.
- server.requestIP is not a function.
AI-assisted analysis of honojs/hono@e2740d5a1b (2026-08-28).
Data as JSON: /api/errors/cd59de2e26d9ac1d.
Report an issue: GitHub.