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
- 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
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
- 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
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
- Connection failures: ECONNREFUSED, ECONNRESET, and friends — why connections get refused, reset, or dropped.
Related errors
- incompatible resource_multipler and spread_factor
- file cache size query returned no rows
- max file cache size query returned no rows
- Non-overlapping bounds: other.max = {} was less than self.mi
- Non-overlappinng bounds: self.max = {} was less than other.m
AI-assisted analysis of neondatabase/neon@8f60b04da4 (2026-08-16).
Data as JSON: /api/errors/936e96cd81db8609.
Report an issue: GitHub.