nautechsystems/nautilus_trader · error · anyhow::Error
Market shard receiver unavailable after connect
Error message
Market shard receiver unavailable after connect
What it means
When the WebSocket shard pool grows (connect_new_shard), it creates a new market client, connects, and then must take ownership of the client's message receiver. If take_message_receiver returns None after a successful connect, the pool's internal invariant is broken — the receiver was already taken or was never set — so the shard cannot be brought up and this error aborts connect_new_shard (invoked from assign).
Source
Thrown at crates/adapters/polymarket/src/websocket/pool.rs:659
async fn connect_new_shard(&self, is_primary: bool) -> anyhow::Result<usize> {
if self.closed.load(Ordering::Acquire) {
anyhow::bail!("Market connection pool is closed");
}
let id = if is_primary {
PRIMARY_SHARD_ID
} else {
let state = self.state.lock();
available_shard_id(&state)
};
let mut client = self.market_client(self.subscribe_new_markets, id);
client.connect().await?;
let handle = client.clone_subscription_handle();
let rx = client
.take_message_receiver()
.ok_or_else(|| anyhow::anyhow!("Market shard receiver unavailable after connect"))?;
let forwarder = match self.spawn_forwarder(rx, is_primary) {
Ok(forwarder) => forwarder,
Err((e, forwarder)) => {
let shard = Box::new(ShardEntry {
client,
handle,
forwarder,
owned: 0,
closing: true,
});
if let Err(close_error) = self.close_shard(id, shard).await {
anyhow::bail!(
"Failed to start market shard forwarder: {e}; startup rollback failed: \
{close_error}"
);
}
anyhow::bail!("Failed to start market shard forwarder: {e}");View on GitHub (pinned to 18893faf8b)
Solutions
- Check that each ShardEntry/market client is used exactly once — never reuse a connected client for another shard
- Guard pool resizing against concurrent assign calls (serialize shard creation)
- Upgrade the polymarket adapter — this indicates an internal invariant break that may be a fixed bug
- Capture the client state at failure and file an issue with logs if reproducible
Example fix
// before: panics the whole assign flow on None
let rx = client.take_message_receiver()
.ok_or_else(|| anyhow::anyhow!("Market shard receiver unavailable after connect"))?;
// after: retry shard creation once
let rx = client.take_message_receiver()
.or_else(|| { client.connect(); client.take_message_receiver() })
.ok_or_else(|| anyhow::anyhow!("Market shard receiver unavailable after connect"))?; Defensive patterns
Strategy: try-catch
Try / catch
match connect_new_shard(id).await {
Ok(shard) => /* register shard */,
Err(e) if e.to_string().contains("receiver unavailable") => {
log::error!("pool invariant broken: {e}; rebuilding pool");
// rebuild or restart the pool
}
Err(e) => return Err(e),
} Prevention
- Never reuse a connected market client across shards
- Serialize pool-resize operations to avoid racing on receivers
- Keep the adapter at a version where pool connect/take_receiver pairing is intact
When it happens
Trigger: Calling connect_new_shard when the freshly constructed client's receiver channel was already consumed, or the client implementation changed so no receiver is created during connect().
Common situations: Concurrent pool resizing racing on the same client; a version mismatch/bug in the market client that skips receiver setup; reusing a client instance for a second shard.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Failed to start market shard forwarder: {e}
- Polymarket data shutdown failed: {}
- Expected BinaryOption, was {other:?}
- RTDS task owner was dropped
- Polymarket RTDS task owner was dropped
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/e42563147ca968a7.
Report an issue: GitHub.