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
- Serialize client lifecycle: never call disconnect() concurrently with connect()
- Create a new generation by calling connect() after shutdown completes (connect restarts the generation)
- 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
- Sequence lifecycle operations with an explicit state machine (Disconnected -> Connecting -> Connected -> Disconnecting)
- Await full disconnect completion before any reconnect
- Avoid issuing connects from shutdown hooks
- Add jittered backoff to reconnect loops
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
- Failed to start Polymarket WebSocket handler task: {e}
- failed to register Polymarket instrument refresh: {e}
- failed to register Polymarket resolve poll: {e}
- Failed to terminate Polymarket data tasks: {e}
- Failed to start Polymarket task generation: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/a6b96c0967d4679a.
Report an issue: GitHub.