nautechsystems/nautilus_trader · error · anyhow::Error

Polymarket WebSocket startup rollback failed: {shutdown_erro

Error message

Polymarket WebSocket startup rollback failed: {shutdown_error}

What it means

During Polymarket WebSocket startup (start_ws_stream, invoked from connect_client), if the spawned user-stream handler task fails immediately, the client attempts a rollback via ws_client.disconnect(). If that rollback disconnect ALSO fails, the original error is re-wrapped with "Polymarket WebSocket startup rollback failed: {shutdown_error}" so both failures are visible. It signals a broken WebSocket lifecycle where neither start nor clean teardown succeeded.

Source

Thrown at crates/adapters/polymarket/src/execution/lifecycle.rs:404

                                }
                            }
                        };

                        if let Err(e) = session_spawner.spawn(future) {
                            log::debug!("Skipping reconnect refresh during shutdown: {e}");
                        }
                    }
                    None => {
                        log::debug!("User WebSocket stream ended");
                        break;
                    }
                }
            }

            log::debug!("User WebSocket handler task completed");
        }) {
            if let Err(shutdown_error) = self.ws_client.disconnect().await {
                return Err(anyhow::Error::new(e).context(format!(
                    "Polymarket WebSocket startup rollback failed: {shutdown_error}"
                )));
            }
            return Err(e.into());
        }

        Ok(())
    }

    async fn teardown_partial_connect(&mut self) -> anyhow::Result<()> {
        self.stopping.store(true, Ordering::Release);
        self.clear_order_event_subscription();
        self.clear_position_event_subscription();
        self.abort_session_tasks();
        self.abort_pending_tasks();
        self.ws_client.begin_shutdown();

        if let Err(e) = self.ws_client.disconnect().await {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Fix the ORIGINAL startup error (first error in the anyhow chain) — the rollback message is secondary.
  2. Check Polymarket WS credentials and endpoint URL configuration.
  3. Verify network reachability of the Polymarket WebSocket host.
  4. Ensure the client is fully dropped/recreated rather than reused after a failed connect.
  5. Add backoff between reconnect attempts so state can settle before reconnecting.
Defensive patterns

Strategy: fallback

Validate before calling

// validate WS config before connect
assert!(!ws_url.is_empty() && ws_url.starts_with("wss://"), "valid WS URL");
assert!(credentials_present(), "API credentials configured");

Try / catch

match client.connect().await {
    Ok(()) => {}
    Err(e) => {
        error!("connect failed (incl. rollback): {e:#}");
        drop(client); // discard possibly-corrupt client state
        let mut fresh = new_client(config)?;
        backoff_retry(|| fresh.connect()).await?;
    }
}

Prevention

When it happens

Trigger: Calling connect on a Polymarket execution/data client where the user WebSocket handler task errors during startup (auth failure, bad URL, network error) and the subsequent disconnect() call also errors (e.g. socket already broken, internal state inconsistent).

Common situations: Invalid or missing Polymarket WebSocket credentials; unreachable host / DNS failure during startup; calling connect while a previous connection is half-torn-down; aggressive reconnect loops compounding state corruption.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/115ffc620555b6d4. Report an issue: GitHub.