nautechsystems/nautilus_trader · error · anyhow::Error

Polymarket task admission is closed: {e}

Error message

Polymarket task admission is closed: {e}

What it means

register_message_handler first obtains a spawner handle from the Polymarket task group via tasks.spawner(). If the task group is closed or shutting down, the spawner cannot be obtained and this error is returned, aborting WS message-handler registration during connect.

Source

Thrown at crates/adapters/polymarket/src/data/lifecycle.rs:93

    }

    fn register_message_handler(
        &self,
        mut rx: tokio::sync::mpsc::UnboundedReceiver<PolymarketWsMessage>,
    ) -> anyhow::Result<()> {
        let cancellation = self.cancellation_token.clone();

        seed_token_meta_from_live_instruments(
            self.clock.get_time_ns(),
            &self.closed_condition_ids,
            &self.instruments,
            &self.token_meta,
        );

        let task_spawner = self
            .tasks
            .spawner()
            .map_err(|e| anyhow::anyhow!("Polymarket task admission is closed: {e}"))?;
        let ctx = WsMessageContext {
            clock: self.clock,
            data_sender: self.data_sender.clone(),
            token_meta: self.token_meta.clone(),
            instruments: self.instruments.clone(),
            instrument_update_state: self.instrument_update_state.clone(),
            gamma_client: self.provider.http_client().clone(),
            filters: self.provider.filters(),
            order_books: self.order_books.clone(),
            last_quotes: self.last_quotes.clone(),
            active_quote_subs: self.active_quote_subs.clone(),
            active_delta_subs: self.active_delta_subs.clone(),
            active_trade_subs: self.active_trade_subs.clone(),
            active_instrument_status_subs: self.active_instrument_status_subs.clone(),
            active_instrument_close_subs: self.active_instrument_close_subs.clone(),
            closed_condition_ids: self.closed_condition_ids.clone(),
            ws_open_tokens: self.ws_open_tokens.clone(),
            ws_sub_mutex: self.ws_sub_mutex.clone(),

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Serialize client lifecycle: never call disconnect() concurrently with connect()
  2. Create a new generation by calling connect() after shutdown completes (connect restarts the generation)
  3. Check that application shutdown is not cancelling the client's runtime
Defensive patterns

Strategy: retry

Validate before calling

// Ensure no disconnect in flight before connecting
if client.is_disconnecting() { return Err(anyhow!("cannot connect while disconnecting")); }

Try / catch

if let Err(e) = client.connect().await {
    if e.to_string().contains("task admission is closed") {
        tokio::time::sleep(Duration::from_secs(1)).await;
        client.connect().await?;
    }
}

Prevention

When it happens

Trigger: Calling connect()/connect_client while the client's task group has begun shutdown (begin_shutdown called by a prior disconnect), so tasks.spawner() returns Err.

Common situations: Reconnect after an intentional disconnect in the same client generation; shutdown hook firing while connect is still executing; concurrent connect/disconnect calls from different tasks.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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