nautechsystems/nautilus_trader · error
Market connection pool is closed
Error message
Market connection pool is closed
What it means
PolymarketConnectionPool serializes subscriptions with wire_mutex and tracks a closed flag. subscribe_new_markets_feed first takes the wire lock, then checks `closed`; if the pool has already been shut down it cannot establish the new-markets feed and returns this error instead.
Source
Thrown at crates/adapters/polymarket/src/websocket/pool.rs:278
*self.inner.out_tx.lock() = Some(out_tx);
*self.inner.out_rx.lock() = Some(out_rx);
self.inner.connect_new_shard(true).await?;
Ok(())
}
/// Sends the new-market discovery subscribe on the primary shard.
///
/// # Errors
///
/// Returns an error if no primary shard is available.
pub async fn subscribe_new_markets_feed(&self) -> anyhow::Result<()> {
let _wire = self.inner.wire_mutex.lock().await;
let handle = {
let state = self.inner.state.lock();
if self.inner.closed.load(Ordering::Acquire) {
anyhow::bail!("Market connection pool is closed");
}
state
.shards
.get(&PRIMARY_SHARD_ID)
.map(|shard| shard.handle.clone())
};
match handle {
Some(handle) => handle.subscribe_market(vec![]).await,
None => anyhow::bail!("No primary market shard available for new-market discovery"),
}
}
/// Takes the merged message receiver, leaving `None` in its place.
#[must_use]
pub fn take_message_receiver(
&self,
) -> Option<tokio::sync::mpsc::UnboundedReceiver<PolymarketWsMessage>> {View on GitHub (pinned to 18893faf8b)
Solutions
- Check pool.is_closed() (or equivalent) before subscribing, and recreate the pool with connect() if closed
- Fix shutdown ordering so subscribers stop before the pool is disconnected
- Recreate or reconnect the pool and retry subscribe_new_markets_feed
- Hold a single long-lived pool reference instead of caching disconnected instances
Example fix
// before
pool.subscribe_new_markets_feed().await?;
// after
if pool.is_closed() {
pool = PolymarketConnectionPool::connect(...).await?;
}
pool.subscribe_new_markets_feed().await?; Defensive patterns
Strategy: validation
Validate before calling
if pool.is_closed() {
pool = PolymarketConnectionPool::connect(config).await?;
}
pool.subscribe_new_markets_feed().await?; Try / catch
match pool.subscribe_new_markets_feed().await {
Ok(()) => {},
Err(e) if e.to_string().contains("pool is closed") => {
let mut pool = pool;
pool = reconnect_pool().await?;
pool.subscribe_new_markets_feed().await?;
}
Err(e) => return Err(e),
} Prevention
- Stop all subscriber tasks before closing the pool
- Check the closed flag before any subscription call
- Recreate the pool after disconnect instead of reusing the old instance
When it happens
Trigger: Calling subscribe_new_markets_feed() on a pool after disconnect()/close() was invoked (or the pool auto-closed), or on a stale pool reference retained past shutdown.
Common situations: Shutdown ordering bugs where a background task subscribes to the new-markets feed after the pool is closed; reconnect logic operating on an old pool instance; keeping the pool alive across a trader stop/start cycle.
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
- conflicting RTDS TWAP observation topic={} symbol={} timesta
- Unsupported RTDS custom data type: {other}
- Failed to start Polymarket WebSocket handler task: {e}
- subscribe_market() requires a market-channel client (created
- unsubscribe_market() requires a market-channel client (creat
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/90e9cb94189adef5.
Report an issue: GitHub.