nautechsystems/nautilus_trader · critical
Cannot take ownership - other references exist
Error message
Cannot take ownership - other references exist
What it means
BitmexWebSocketClient::stream() consumes the single `Arc`-wrapped broadcast receiver (`out_rx`) by `take()`-ing it and then calling `Arc::try_unwrap`. The panic fires when other `Arc` clones still exist, meaning the receiver is shared and exclusive ownership cannot be obtained. The library requires that `stream()` be called exactly once and that no other holder of the receiver remains.
Source
Thrown at crates/adapters/bitmex/src/websocket/client.rs:644
))
})?;
Ok(())
}
/// Provides the internal stream as a channel-based stream.
///
/// # Panics
///
/// This function panics:
/// - If the websocket is not connected.
/// - If `stream` has already been called somewhere else (stream receiver is then taken).
pub fn stream(&mut self) -> impl Stream<Item = BitmexWsMessage> + use<> {
let rx = self
.out_rx
.take()
.expect("Stream receiver already taken or not connected");
let mut rx = Arc::try_unwrap(rx).expect("Cannot take ownership - other references exist");
async_stream::stream! {
while let Some(msg) = rx.recv().await {
yield msg;
}
}
}
/// Closes the client.
///
/// # Errors
///
/// Returns an error if the WebSocket is not connected or if closing fails.
pub async fn close(&mut self) -> Result<(), BitmexWsError> {
log::debug!("Starting close process");
self.signal.store(true, Ordering::Relaxed);
// Send Disconnect command to handlerView on GitHub (pinned to 18893faf8b)
Solutions
- Call `stream()` at most once per client connection and drop any previously obtained stream before calling again.
- Create a fresh BitmexWebSocketClient (or reconnect) for each independent consumer instead of sharing one receiver.
- If broadcast semantics to multiple consumers are needed, subscribe/broadcast upstream rather than unwrapping the single Arc.
- Ensure no background task still holds a clone of the receiver when `stream()` is called.
Example fix
// before let s1 = client.stream(); let s2 = client.stream(); // panics: other references exist // after let s1 = client.stream(); // single consumer; drop s1 before re-streaming // or: build a second client for the second consumer let s2 = other_client.stream();
Defensive patterns
Strategy: validation
Validate before calling
// Call stream() exactly once per client; track with a flag
if stream_already_created {
panic!("stream() already called; reuse the existing stream or create a new client");
} Try / catch
// Rust panics cannot be caught except via catch_unwind; prefer
let stream = client.stream(); // keep the returned stream; never call stream() again
while let Some(msg) = stream.next().await { /* single consumer only */ } Prevention
- One consumer per BitmexWebSocketClient; create a new client for additional consumers.
- Never clone or share the internal receiver; use the returned stream directly.
- Drop an old stream before reconnecting and re-streaming.
When it happens
Trigger: Calling `client.stream()` while another clone of the internal `Arc<Receiver<BitmexWsMessage>>` is still alive (e.g. a previously obtained stream is still running, or a clone was taken for another task).
Common situations: Calling `stream()` twice on the same client; spawning two consumers on one WebSocket client; keeping a reference to the stream alive while reconnecting/re-creating the stream.
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
- InstrumentState channel requires kind and currency parameter
- Stream receiver already taken or client not connected - stre
- Cannot take ownership of stream - client was cloned and othe
- Stream receiver already taken or client not connected - stre
- Cannot take ownership of stream - client was cloned and othe
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/3f22cb53091397f7.
Report an issue: GitHub.