nautechsystems/nautilus_trader · error · anyhow::Error
failed to register Polymarket instrument refresh: {e}
Error message
failed to register Polymarket instrument refresh: {e} What it means
Thrown by register_instrument_refresh_task when self.tasks.spawn(future) fails, meaning the Polymarket data client's task group refused to admit the periodic instrument-refresh background task. This typically happens because the task group is closed/shutting down (post-disconnect) or the spawner could not accept a new task. connect() then propagates this as the data-client connection error.
Source
Thrown at crates/adapters/polymarket/src/data/instruments.rs:595
{
Ok(total) => {
if total > 0 {
log::debug!(
"Refreshed {total} Polymarket instruments into the live cache"
);
}
}
Err(e) => {
log::error!("Failed to refresh Polymarket instruments: {e}");
}
}
}
log::debug!("Polymarket instrument refresh task ended");
};
self.tasks.spawn(future).map_err(|e| {
anyhow::anyhow!("failed to register Polymarket instrument refresh: {e}")
})?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use std::{
net::SocketAddr,
sync::atomic::{AtomicUsize, Ordering},
};
use axum::{
Json, Router,
extract::{RawQuery, State},
http::StatusCode,
response::{IntoResponse, Response},
routing::get,View on GitHub (pinned to 18893faf8b)
Solutions
- Ensure disconnect()/cancel is not racing connect(): await or drop the disconnect before calling connect
- Do not call connect() during application shutdown; check client state first
- Verify the tokio runtime is alive for the duration of connect()
- Retry the connect() on a fresh client instance; the task generation is restarted on next connect
Example fix
// before: racing calls client.connect(); client.disconnect(); // after: sequential lifecycle client.disconnect().await?; client.connect().await?;
Defensive patterns
Strategy: try-catch
Validate before calling
// Rust: check lifecycle state before connecting assert!(!is_disconnecting(&client), "client is shutting down; do not connect");
Type guard
fn is_connectable(client: &PolymarketDataClient) -> bool { !client.is_disconnecting() && runtime_is_alive() } Try / catch
match client.connect().await {
Err(e) if e.to_string().contains("failed to register Polymarket instrument refresh") => {
log::warn!("connect raced shutdown; retrying");
client.connect().await?;
}
r => r?,
} Prevention
- Never call connect() and disconnect() concurrently on the same client
- Keep the tokio runtime alive for the full client lifecycle
- Gate connects on an application-level lifecycle state machine
- On failure, retry connect() on the same client only after prior shutdown fully completes
When it happens
Trigger: Calling connect()/connect_client while the client's TaskGroup is shutting down or already closed, so tasks.spawn() rejects the instrument refresh future; also any internal spawn error (e.g. runtime shutdown in progress).
Common situations: Concurrent disconnect() racing with connect(); reconnect attempt issued after cancellation was initiated; app shutdown triggering disconnect while a connect is still completing; dropping the tokio runtime while client connect is in flight.
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 register Polymarket resolve poll: {e}
- Failed to start RTDS message loop: {e}; startup rollback fai
- Failed to start Polymarket WebSocket handler task: {e}
- Failed to register Betfair keep-alive task: {e}
- Failed to register Betfair reconnect task: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/c7aab31d739cf48c.
Report an issue: GitHub.