If your WebSocket connection repeatedly closes every minute with error code 1006, the issue is likely a proxy or middlebox cutting the connection due to an idle timeout. The simple solution is implementing server-initiated «heartbeats» to keep it alive.
Ever wonder why your WebSocket or Server-Sent Events (SSE) connection mysteriously drops every minute, showing error code 1006 in your browser console? You're not alone, and it often points to a “silent watcher” in your network. For developers, these consistent disconnections are frustrating and lead to poor user experiences, but more importantly, understanding the root cause and its solution is key. This isn't a bug in your message handling code; it's a network configuration challenge.
When your connection consistently dies at suspiciously regular intervals—like 60, 55, or even 30 seconds—and neither your server nor the browser explicitly sends a close frame, it's typically due to an 'idle timeout' on a device sitting between your client and server. This device, often an L7 proxy or load balancer, forcibly cuts the TCP connection when no application-level bytes flow for a specific duration. Error code 1006 means 'abnormal closure,' which is precisely the signature of a middlebox dropping the TCP socket: it decides the connection is idle, closes both sides, and neither endpoint gets a proper WebSocket-level close notification. What makes it tricky is that local development often works perfectly because there's no such proxy in the path.
You might think of TCP keepalives, but unfortunately, they don't solve this. An L7 proxy terminates TCP on both sides, meaning TCP keepalive probes from your server never reach the proxy's 'was there data?' counter. It only cares about application bytes. The solution isn't to simply request a longer timeout. Instead, it involves implementing server-initiated «heartbeats». These are small, application-level messages sent regularly—at an interval shorter than the strictest idle timeout along the network path. This ensures that bytes are always moving, preventing any proxy from deeming the connection idle and closing it. The client should also be designed to gracefully reconnect without panicking if a disconnection does occur. So, the next time you encounter a recurring 1006 error, remember it's not a flaw in your application logic but a network timer needing a regular «heartbeat» to stay alive and well!
When your connection consistently dies at suspiciously regular intervals—like 60, 55, or even 30 seconds—and neither your server nor the browser explicitly sends a close frame, it's typically due to an 'idle timeout' on a device sitting between your client and server. This device, often an L7 proxy or load balancer, forcibly cuts the TCP connection when no application-level bytes flow for a specific duration. Error code 1006 means 'abnormal closure,' which is precisely the signature of a middlebox dropping the TCP socket: it decides the connection is idle, closes both sides, and neither endpoint gets a proper WebSocket-level close notification. What makes it tricky is that local development often works perfectly because there's no such proxy in the path.
You might think of TCP keepalives, but unfortunately, they don't solve this. An L7 proxy terminates TCP on both sides, meaning TCP keepalive probes from your server never reach the proxy's 'was there data?' counter. It only cares about application bytes. The solution isn't to simply request a longer timeout. Instead, it involves implementing server-initiated «heartbeats». These are small, application-level messages sent regularly—at an interval shorter than the strictest idle timeout along the network path. This ensures that bytes are always moving, preventing any proxy from deeming the connection idle and closing it. The client should also be designed to gracefully reconnect without panicking if a disconnection does occur. So, the next time you encounter a recurring 1006 error, remember it's not a flaw in your application logic but a network timer needing a regular «heartbeat» to stay alive and well!