windmill-labs/windmill · error

Bad Gateway

Error message

Bad Gateway

What it means

multiplayer/gateway.mjs runs an HTTP proxy in front of per-instance multiplayer servers. Its proxy 'error' handler writes a 502 (if headers were not already sent) and ends the response with 'Bad Gateway'. It means the gateway could not complete the proxied request to the target port.

Source

Thrown at multiplayer/gateway.mjs:69

  const { port, path } = resolve(clientReq.url)

  const opts = {
    hostname: '127.0.0.1',
    port,
    path,
    method: clientReq.method,
    headers: clientReq.headers,
  }

  const proxy = http.request(opts, (proxyRes) => {
    clientRes.writeHead(proxyRes.statusCode, proxyRes.headers)
    proxyRes.pipe(clientRes, { end: true })
  })

  proxy.on('error', (err) => {
    console.error(`[gateway] HTTP proxy error → :${port}${path}: ${err.message}`)
    if (!clientRes.headersSent) {
      clientRes.writeHead(502, { 'Content-Type': 'text/plain' })
    }
    clientRes.end('Bad Gateway')
  })

  clientReq.pipe(proxy, { end: true })
})

// ---- WebSocket proxy (upgrade) ----

server.on('upgrade', (clientReq, clientSocket, head) => {
  const { port, path } = resolve(clientReq.url)

  const opts = {
    hostname: '127.0.0.1',
    port,
    path,
    method: 'GET',
    headers: clientReq.headers,

View on GitHub (pinned to e474e8803c)

Solutions

  1. Check gateway logs for '[gateway] HTTP proxy error' — the message names the target port and path
  2. Verify the instance server is running and listening on the port the gateway routed to
  3. Fix or refresh the instance registry/routing entry so it points at a live port
  4. Retry the request once the instance is healthy

Example fix

// before
curl http://gateway/room/1  # instance on :7103 is down → 502
// after
docker start multiplayer-instance-7103  # then retry; gateway proxies successfully
Defensive patterns

Strategy: retry

Validate before calling

// before routing to an instance port, probe it
const healthy = await fetch(`http://127.0.0.1:${port}/health`).then(r => r.ok).catch(() => false);
if (!healthy) throw new Error(`multiplayer instance on :${port} is not up`);

Try / catch

try {
  const res = await fetch(gatewayUrl + path);
  if (res.status === 502) {
    // instance down; re-check registry and retry after restart
  }
} catch (err) { /* network-level failure of the gateway itself */ }

Prevention

When it happens

Trigger: A request arrives at the gateway and is proxied to :<port><path>, but the target connection errors: nothing listening on that port, ECONNRESET from the instance server, or the socket closing before a response.

Common situations: Multiplayer instance container/process not started yet or already stopped; stale routing table pointing at a dead port; instance crashing under load and resetting connections; port mapping mismatch between gateway and instances.

Understand the failure class

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/e661087864725970. Report an issue: GitHub.