neondatabase/neon · critical

dispatcher connection closed

Error message

dispatcher connection closed

What it means

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.

Source

Thrown at libs/vm_monitor/src/runner.rs:507

                                            },
                                            message.id
                                        )
                                    }
                                };

                                self.dispatcher
                                    .send(out)
                                    .await
                                    .context("failed to send message")?;
                            }
                            Err(e) => warn!(
                                error = format_args!("{e:#}"),
                                msg = ?msg,
                                "received error message"
                            ),
                        }
                    } else {
                        anyhow::bail!("dispatcher connection closed")
                    }
                }
            }
        }
    }
}

View on GitHub (pinned to 8f60b04da4)

Solutions

  1. Check why the peer closed: autoscaler-agent logs, control-plane events, network policy changes
  2. Restart the vm-monitor process so it re-establishes a fresh WebSocket session
  3. Verify proxies/load balancers in the path are not timing out idle WebSocket connections (align ping/keepalive)
  4. If this happens during planned shutdown, make exit handling treat it as a clean stop rather than a failure
Defensive patterns

Strategy: retry

Try / catch

match runner.run().await {
    Ok(()) => {}
    Err(e) if e.to_string().contains("dispatcher connection closed") => {
        // reconnect with backoff instead of crashing
        restart_monitor_with_backoff().await;
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Related errors


AI-assisted analysis of neondatabase/neon@8f60b04da4 (2026-08-16). Data as JSON: /api/errors/936e96cd81db8609. Report an issue: GitHub.