nautechsystems/nautilus_trader · error
failed to subscribe to user portfolio: {e}
Error message
failed to subscribe to user portfolio: {e} What it means
Raised in `DeribitExecutionClient::connect` when the private-channel subscription for user portfolio (`subscribe_user_portfolio`) fails, as the last of the three execution subscriptions. Connect aborts since portfolio/margin updates are needed for account-state tracking. On the subsequent subscription-confirmation timeout the client rolls back by unsubscribing all three channels.
Source
Thrown at crates/adapters/deribit/src/execution.rs:571
.authenticate_session(DERIBIT_EXECUTION_SESSION_NAME)
.await
.map_err(|e| anyhow::anyhow!("failed to authenticate WebSocket session: {e}"))?;
log::debug!("WebSocket client authenticated for execution");
// Subscribe to user order and trade updates for all instruments
self.ws_client
.subscribe_user_orders()
.await
.map_err(|e| anyhow::anyhow!("failed to subscribe to user orders: {e}"))?;
self.ws_client
.subscribe_user_trades()
.await
.map_err(|e| anyhow::anyhow!("failed to subscribe to user trades: {e}"))?;
self.ws_client
.subscribe_user_portfolio()
.await
.map_err(|e| anyhow::anyhow!("failed to subscribe to user portfolio: {e}"))?;
if let Err(e) = self.ws_client.wait_for_subscriptions_confirmed(30.0).await {
// Roll back subscription state so a retry re-sends subscribe requests
let _ = self.ws_client.unsubscribe_user_orders().await;
let _ = self.ws_client.unsubscribe_user_trades().await;
let _ = self.ws_client.unsubscribe_user_portfolio().await;
anyhow::bail!("subscription confirmation failed: {e}");
}
log::debug!("Subscribed to user order, trade, and portfolio updates");
// Spawn stream handler to dispatch WebSocket messages to the execution engine
let stream = self.ws_client.stream()?;
self.spawn_stream_handler(stream)?;
Ok::<(), anyhow::Error>(())
}
.await;View on GitHub (pinned to 18893faf8b)
Solutions
- Read the embedded inner error for the actual cause (transport vs JSON-RPC rejection).
- Retry connect; the rollback/unsubscribe logic ensures a clean re-subscription attempt.
- Verify the account has permission for portfolio channels and credentials are correctly configured for the target environment.
- Check network stability and proxy timeouts around the connect window.
- Reduce subscription load or stagger clients if hitting Deribit subscription limits.
Defensive patterns
Strategy: retry
Try / catch
// connect() already rolls back subscriptions on failure; simply retry
match client.connect().await {
Err(e) if format!("{e:#}").contains("failed to subscribe to user portfolio") => {
tokio::time::sleep(BACKOFF).await;
client.connect().await?;
}
other => other?,
} Prevention
- Confirm account-level permission for portfolio channels.
- Check credentials/environment (testnet vs mainnet) match the intended account.
- Retry connect after failures — the client unsubscribes all user channels first for a clean re-subscribe.
- Limit concurrent private subscriptions to stay within venue limits.
When it happens
Trigger: Calling `connect()` where orders and trades subscriptions succeed but `ws_client.subscribe_user_portfolio().await` returns Err — connection failure on the third RPC, rejected `user.portfolio.*` channel subscribe, or session invalidation before this call.
Common situations: Same family as the other subscribe failures: credential scope problems, mid-handshake network drops, channel/quota rejection, environment (testnet/prod) mismatch, or an already-closed ws client.
Understand the failure class
Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.
Related errors
- subscription confirmation failed: {e}
- failed to subscribe to user orders: {e}
- failed to subscribe to user trades: {e}
- {e}
- {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/ad7fcbfb1bf77ef8.
Report an issue: GitHub.