{"record":{"id":"936e96cd81db8609","repo":"neondatabase/neon","slug":"dispatcher-connection-closed","errorCode":null,"errorMessage":"dispatcher connection closed","messagePattern":"dispatcher connection closed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"libs/vm_monitor/src/runner.rs","lineNumber":507,"sourceCode":"                                            },\n                                            message.id\n                                        )\n                                    }\n                                };\n\n                                self.dispatcher\n                                    .send(out)\n                                    .await\n                                    .context(\"failed to send message\")?;\n                            }\n                            Err(e) => warn!(\n                                error = format_args!(\"{e:#}\"),\n                                msg = ?msg,\n                                \"received error message\"\n                            ),\n                        }\n                    } else {\n                        anyhow::bail!(\"dispatcher connection closed\")\n                    }\n                }\n            }\n        }\n    }\n}\n","sourceCodeStart":489,"sourceCodeEnd":514,"githubUrl":"https://github.com/neondatabase/neon/blob/8f60b04da47ffefe0e52bda2440134b42874eb75/libs/vm_monitor/src/runner.rs#L489-L514","documentation":"In the vm-monitor's main run loop, the dispatcher's WebSocket stream to the Neon autoscaling control plane yielded `None`, which for async streams means the stream is exhausted — the connection was closed. The monitor bails immediately because every subsequent operation depends on that channel; the error typically surfaces from `Runner::run` as the process exit reason.","triggerScenarios":"The WebSocket between vm-monitor and the autoscaler-agent/control plane closes while the loop awaits messages: remote side closed the session, intermediary dropped it, or the dispatcher was shut down as part of teardown.","commonSituations":"Restart/migration of the autoscaler component on the other end; network interruptions between compute and control plane; load balancers killing idle WebSocket connections; the monitor outliving its parent agent.","solutions":["Check why the peer closed: autoscaler-agent logs, control-plane events, network policy changes","Restart the vm-monitor process so it re-establishes a fresh WebSocket session","Verify proxies/load balancers in the path are not timing out idle WebSocket connections (align ping/keepalive)","If this happens during planned shutdown, make exit handling treat it as a clean stop rather than a failure"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"match runner.run().await {\n    Ok(()) => {}\n    Err(e) if e.to_string().contains(\"dispatcher connection closed\") => {\n        // reconnect with backoff instead of crashing\n        restart_monitor_with_backoff().await;\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Run the monitor under a supervisor that restarts on connection loss with backoff","Align WebSocket keepalive/ping settings with intermediary proxy timeouts","Distinguish expected shutdown from unexpected close in exit handling"],"tags":["rust","neon","vm-monitor","websocket","connection"],"backgroundTag":"connection-closed","analyzedSha":"8f60b04da47ffefe0e52bda2440134b42874eb75","analyzedAt":"2026-08-16T23:39:28.135Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}