windmill-labs/windmill · error
Bad Gateway
Error message
Bad Gateway
What it means
The dev proxy in cli/src/commands/dev/dev.ts forwards each client request to an upstream server. When the outbound proxyReq emits an 'error' (target unreachable, connection reset, TLS failure), the handler logs the cause and responds to the client with HTTP 502 and the body 'Bad Gateway'. This is the proxy signaling that the upstream failed, not the client request itself.
Source
Thrown at cli/src/commands/dev/dev.ts:873
path: clientReq.url,
method: clientReq.method,
headers: fwdHeaders,
};
const proxyReq = httpModule.request(proxyOpts, (proxyRes) => {
const setCookie = proxyRes.headers["set-cookie"];
if (setCookie) {
proxyRes.headers["set-cookie"] = setCookie.map((cookie) =>
cookie.replace(/domain=[^;]+/gi, "domain=localhost")
);
}
clientRes.writeHead(proxyRes.statusCode ?? 502, proxyRes.headers);
proxyRes.pipe(clientRes, { end: true });
});
proxyReq.on("error", (err) => {
console.error("Proxy error:", err.message);
clientRes.writeHead(502);
clientRes.end("Bad Gateway");
});
clientReq.pipe(proxyReq, { end: true });
});
// WebSocket upgrades
proxyServer.on("upgrade", (req, socket, head) => {
const pathname = req.url?.split("?")[0] ?? "";
if (pathname === "/ws_dev" || pathname === "/ws") {
devWss.handleUpgrade(req, socket, head, (ws) => {
devWss.emit("connection", ws, req);
});
return;
}
if (pathname.startsWith("/ws/") || pathname.startsWith("/ws_mp/") || pathname.startsWith("/ws_debug/")) {View on GitHub (pinned to e474e8803c)
Solutions
- Check the terminal running the dev command for the 'Proxy error:' line — the err.message names the real cause
- Verify the upstream server (backend) is actually running and listening on the configured port
- Confirm the REMOTE/target port env var matches the port the backend binds to
- Restart the dev command after the upstream is healthy; retry the request
Example fix
// before cargo run # not started; proxy calls fail // after cd backend && cargo run # wait for 'listening', then run dev frontend
Defensive patterns
Strategy: retry
Validate before calling
// before issuing requests through the dev proxy, check the upstream is reachable
const upstream = process.env.REMOTE ?? 'http://localhost:8000';
await fetch(upstream + '/api/version').catch(() => { throw new Error(`upstream ${upstream} not reachable — start the backend first`); }); Try / catch
// on the client side of the proxy
try {
const res = await fetch(url);
if (res.status === 502) throw new Error('dev proxy upstream failed — is the backend running?');
} catch (err) { /* surface upstream health message */ } Prevention
- Start the backend before the dev frontend/proxy
- Check for the proxy's 'Proxy error:' log line to diagnose the real cause
- Pin REMOTE/port env vars in one place so proxy and backend agree
- Add a startup health check against the upstream before serving
When it happens
Trigger: Any request proxied to the upstream where the socket errors: upstream port not listening (backend not started or crashed), connection refused/reset, DNS failure, or TLS handshake failure on the target the dev command proxies to.
Common situations: Running the dev frontend before the backend is up or after the backend died; wrong REMOTE/port env var; backend restarted mid-request; firewall or VPN blocking the upstream port.
Understand the failure class
- HTTP status errors: handling 4xx and 5xx responses — how to handle 4xx and 5xx responses properly.
Related errors
- Bad Gateway
- Could not find a free port in the range ${requested}-${reque
- Failed to fetch foundation models for AWS Bedrock
- Failed to fetch models for provider ${provider}
- no pinned address to connect
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/479dc3aa701e19a5.
Report an issue: GitHub.