nautechsystems/nautilus_trader · error

No primary market shard available for new-market discovery

Error message

No primary market shard available for new-market discovery

What it means

The Polymarket market connection pool maintains a designated 'primary' shard used for discovering newly listed markets (subscribing with an empty asset list). This error means no shard with PRIMARY_SHARD_ID exists in the pool when subscribe_new_markets_feed is called — either the pool has not connected yet or the primary shard was closed and not re-established.

Source

Thrown at crates/adapters/polymarket/src/websocket/pool.rs:288

    ///
    /// 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>> {
        self.inner.out_rx.lock().take()
    }

    /// Disconnects every shard and clears routing state.
    ///
    /// # Errors
    ///
    /// Returns an error after attempting every shard when a task or connection does not stop.
    pub async fn disconnect(&self) -> anyhow::Result<()> {
        self.inner.begin_shutdown();

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure pool.connect() has completed successfully before calling subscribe_new_markets_feed
  2. Reconnect the pool (call connect) to re-establish the primary shard, then retry the subscription
  3. Check shard lifecycle: if the primary shard was closed by error/rebalance, verify connect_new_shard(PRIMARY_SHARD_ID) is invoked again
  4. Guard the call by checking the pool's primary shard state before subscribing

Example fix

// before
let pool = MarketPool::new(config);
pool.subscribe_new_markets_feed().await?; // no primary shard yet
// after
let pool = MarketPool::new(config);
pool.connect().await?; // establishes primary shard
pool.subscribe_new_markets_feed().await?;
Defensive patterns

Strategy: fallback

Validate before calling

// ensure the primary shard exists before subscribing
if pool.primary_shard_handle().is_none() {
    pool.connect().await?;
}

Try / catch

match pool.subscribe_new_markets_feed().await {
    Ok(rx) => { /* use feed */ }
    Err(e) if e.to_string().contains("No primary market shard") => {
        pool.connect().await?;
        pool.subscribe_new_markets_feed().await?;
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling subscribe_new_markets_feed before connect() has established the primary market shard, or after the primary shard was closed/removed by pool rebalancing without being reopened.

Common situations: Calling discovery subscription immediately after constructing the pool without connecting; a dropped WebSocket killed the primary shard and it was never restarted; calling the feed after disconnect.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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