nautechsystems/nautilus_trader · error
failed Derive private WS subscriptions
Error message
failed Derive private WS subscriptions
What it means
This error is returned by Derive execution client connect() when subscribing to the private WebSocket channels (orders, balances) fails but the partial-connect teardown succeeded cleanly. The original subscription error is the source; the context confirms startup was rolled back and no partial connection remains. It surfaces from connect().
Source
Thrown at crates/adapters/derive/src/execution.rs:651
}
return Err(e);
};
let subaccount_id = self.credential.subaccount_id();
let channels = vec![
DeriveWsChannel::orders(subaccount_id),
DeriveWsChannel::private_trades(subaccount_id),
DeriveWsChannel::balances(subaccount_id),
];
if let Err(e) = self.ws_client.subscribe_channels(channels).await {
log::warn!("Derive private WS subscriptions failed: {e}; tearing down");
if let Err(teardown_error) = self.teardown_partial_connect().await {
return Err(anyhow::Error::new(e).context(format!(
"Derive execution startup teardown failed: {teardown_error}"
)));
}
return Err(anyhow::Error::new(e).context("failed Derive private WS subscriptions"));
}
if let Err(e) = self.start_ws_dispatch(rx) {
if let Err(teardown_error) = self.teardown_partial_connect().await {
return Err(e.context(format!(
"Derive execution startup teardown failed: {teardown_error}"
)));
}
return Err(e.context("failed to register Derive execution WebSocket dispatch task"));
}
// Fail-fast if the initial account snapshot cannot load: without it,
// `await_account_registered` would block the full timeout window and
// surface a misleading registration timeout. Tear down the WS we
// already started so the caller does not leak the dispatch task.
if let Err(e) = self.refresh_account_state().await {
log::warn!("Initial Derive account state refresh failed: {e}; tearing down");
if let Err(teardown_error) = self.teardown_partial_connect().await {View on GitHub (pinned to 18893faf8b)
Solutions
- Verify Derive API credentials, wallet, and subaccount_id configuration
- Read the chained source error to see the specific subscription rejection
- Retry connect() — transient network/service issues resolve on retry
- Check Derive API status for outages
- Ensure the WS client version/protocol matches the current Derive API
Defensive patterns
Strategy: retry
Validate before calling
// Validate Derive credentials and subaccount before attempting subscription
if !derive_credentials_valid(config) {
return Err(anyhow!("invalid Derive credentials; refusing connect"));
} Type guard
fn is_clean_subscription_failure(err: &anyhow::Error) -> bool {
err.to_string().contains("failed Derive private WS subscriptions")
} Try / catch
match exec_client.connect().await {
Err(e) if is_clean_subscription_failure(&e) => {
// rollback succeeded; safe to retry with backoff
retry_with_backoff(|| exec_client.connect()).await
}
other => other,
} Prevention
- Use exponential backoff on connect retries for transient failures
- Validate API keys, wallet, and subaccount configuration up front
- Check Derive API status before trading sessions
- Keep the WS client/protocol version current with the Derive API
When it happens
Trigger: ws_client.subscribe_channels(channels) returns Err and teardown_partial_connect() completes successfully.
Common situations: Invalid or expired Derive API credentials rejecting subscriptions; Derive rejecting a channel due to wrong subaccount; transient network failure at startup; Derive service outage.
Related errors
- Derive execution startup teardown failed: {teardown_error}
- invalid Derive subscription channel `{channel}`
- WS user data subscription timed out
- Failed to start Spot public JSON WS bytes task: {e}
- Failed to start Spot public JSON WS handler task: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/67bfcd404341a0be.
Report an issue: GitHub.