nautechsystems/nautilus_trader · error
Failed to start RTDS message loop: {e}; startup rollback fai
Error message
Failed to start RTDS message loop: {e}; startup rollback failed: {shutdown_error} What it means
Raised when the RTDS message loop fails to start AND the startup rollback (aborting/joining the just-started task) itself fails to complete cleanly — e.g. the aborted task did not stop within the 2-second join window ('message loop task did not stop after abort'). The combined message reports both the original start error and the rollback failure.
Source
Thrown at crates/adapters/polymarket/src/rtds.rs:970
if let Err(e) = spawn_result {
ws.disconnect().await;
self.clear_ws_if_current(&ws);
let shutdown_error = match finish_task(
&mut message_slot,
Duration::ZERO,
Duration::from_secs(2),
)
.await
{
Some(TaskJoinOutcome::Failed(error)) => {
Some(format!("message loop task failed: {error}"))
}
Some(TaskJoinOutcome::Incomplete) => {
Some("message loop task did not stop after abort".to_string())
}
None | Some(TaskJoinOutcome::Completed(()) | TaskJoinOutcome::Aborted) => None,
};
anyhow::bail!(match shutdown_error {
Some(shutdown_error) => format!(
"Failed to start RTDS message loop: {e}; startup rollback failed: \
{shutdown_error}"
),
None => format!("Failed to start RTDS message loop: {e}"),
});
}
Ok(true)
}
fn is_generation_open(&self, generation: u64) -> bool {
let current_generation = self.inner.shutdown_generation.lock();
*current_generation == generation && !self.inner.closing.load(Ordering::Acquire)
}
fn websocket_config(&self) -> WebSocketConfig {
WebSocketConfig {View on GitHub (pinned to 18893faf8b)
Solutions
- Inspect the inner error first — fix the root cause of the message-loop start failure (usually a panic or invalid initial state).
- Ensure the runtime stays alive until teardown joins complete; do not drop the runtime mid-abort.
- Harden the message loop against early panics by validating state before spawning.
- Check for blocking calls in the abort/join path that prevent the task from stopping.
Example fix
// before
anyhow::bail!(format!("Failed to start RTDS message loop: {e}")); // hides rollback outcome
// after
if let Some(rb) = shutdown_error {
log::error!("RTDS startup rollback failed: {rb}");
}
anyhow::bail!("Failed to start RTDS message loop: {e}"); Defensive patterns
Strategy: try-catch
Try / catch
if let Err(e) = feed.connect().await {
let msg = format!("{e:#}");
if msg.contains("Failed to start RTDS message loop") {
log::error!("RTDS startup failure (check rollback note): {msg}");
// recreate feed; state may be partially torn down
}
return Err(e);
} Prevention
- Fix the underlying message-loop start error first; the rollback failure is secondary.
- Keep the tokio runtime alive until feed teardown completes so aborts can join.
- Avoid panics in the message-loop entry path by validating state before spawn.
- Monitor for this error as a signal of both a startup and a teardown bug.
When it happens
Trigger: spawn_result.is_err() (e.g. the task panics immediately or the spawn hook fails) and finish_task on the aborted message slot returns Incomplete within the 2-second join window.
Common situations: Message-loop task panicking at startup plus a hung join; the tokio runtime shutting down so the aborted task is never polled to completion; a blocked cleanup path in the message loop.
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
- failed to register Polymarket instrument refresh: {e}
- failed to register Polymarket resolve poll: {e}
- Failed to start Hyperliquid WebSocket handler task: {e}
- Failed to start Polymarket WebSocket handler task: {e}
- {e}; subscription rollback failed: {close_error}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/0420b3aab5d456ca.
Report an issue: GitHub.