nautechsystems/nautilus_trader · error
RTDS WebSocket client unavailable after reconcile
Error message
RTDS WebSocket client unavailable after reconcile
What it means
Raised after a reconcile attempts to (re)establish the RTDS WebSocket: ensure_connected_locked returned success but current_ws() still yields no client. This is an internal invariant violation — the code expected ensure_connected_locked to install a WebSocket client whenever subscriptions exist.
Source
Thrown at crates/adapters/polymarket/src/rtds.rs:833
}
}
}
}
async fn reconcile_once(&self, reset_live_state: bool) -> anyhow::Result<()> {
let _guard = self.inner.wire_mutex.lock().await;
if self.inner.closing.load(Ordering::Acquire) {
return Ok(());
}
if !self.has_subscriptions() && self.current_ws().is_none() {
return Ok(());
}
let fresh_connect = self.ensure_connected_locked().await?;
let Some(ws) = self.current_ws() else {
anyhow::bail!("RTDS WebSocket client unavailable after reconcile");
};
self.reconcile_live_locked(&ws, fresh_connect || reset_live_state)
.await
}
async fn ensure_connected_locked(&self) -> anyhow::Result<bool> {
let generation = {
let generation = self.inner.shutdown_generation.lock();
if self.inner.closing.load(Ordering::Acquire) {
return Ok(false);
}
*generation
};
if self.current_ws().is_some_and(|ws| !ws.is_disconnected()) {
return Ok(false);View on GitHub (pinned to 18893faf8b)
Solutions
- Ensure ensure_connected_locked always either installs a client or returns an error; propagate shutdown bails instead of swallowing them.
- Hold the state lock across connect and the ws lookup so shutdown cannot clear the client in between.
- Re-check the shutdown/generation state after ensure_connected_locked and return a cancellation error instead.
- If it persists, file a bug: this indicates a real invariant break in the feed's connect logic.
Example fix
// before
let fresh_connect = self.ensure_connected_locked().await?;
let Some(ws) = self.current_ws() else {
anyhow::bail!("RTDS WebSocket client unavailable after reconcile");
};
// after
let fresh_connect = self.ensure_connected_locked().await?;
if !self.is_generation_open(generation) {
anyhow::bail!("RTDS reconcile was canceled by shutdown");
}
let Some(ws) = self.current_ws() else {
anyhow::bail!("RTDS WebSocket client unavailable after reconcile");
}; Defensive patterns
Strategy: retry
Validate before calling
// before reconcile
if !feed.has_subscriptions() && !feed.has_ws_client() {
return Ok(());
}
if feed.is_shutdown() {
return Ok(());
} Try / catch
if let Err(e) = feed.reconcile().await {
if e.to_string().contains("unavailable after reconcile") {
log::error!("RTDS reconcile invariant violated: {e:#}");
// recreate the feed instance
}
return Err(e);
} Prevention
- Do not swallow errors from connect/reconnect helpers — propagate them so invariants stay intact.
- Serialize lifecycle operations; avoid concurrent reconcile/shutdown calls.
- Recreate the feed instance if this error appears; internal state is inconsistent.
- Report persistent occurrences as a bug with logs around the connect path.
When it happens
Trigger: ensure_connected_locked returns Ok without installing a client while has_subscriptions() is true and no WebSocket client is stored — e.g. a swallowed shutdown bail in the connect path, or a race where the installed client was cleared between connect and lookup.
Common situations: Concurrent shutdown clearing ws_client while reconcile runs; subscriptions added just as the feed is being torn down; a modified connect path that returns Ok without storing the client.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- WS message receiver not available after connect
- noid '{}' does not match new order oid '{}'
- Polymarket data shutdown failed: {}
- Expected 2 token IDs, received {}
- Expected 2 outcomes, received {}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/94448f177835abe5.
Report an issue: GitHub.