nautechsystems/nautilus_trader · error
Authentication failed: {e}; handler shutdown failed: {shutdo
Error message
Authentication failed: {e}; handler shutdown failed: {shutdown_error} What it means
This is the compound variant of the OKX WebSocket authentication failure: auth failed AND the subsequent handler-shutdown/teardown also failed, so both errors are reported together. It surfaces the original auth error plus the shutdown error to avoid hiding either failure during rollback.
Source
Thrown at crates/adapters/okx/src/websocket/client.rs:894
control.register(move || reconnect_handle.request_reconnect());
}
log::debug!("Sent WebSocket client to handler");
if self.credential.is_some()
&& let Err(e) = self.authenticate().await
{
self.handler_tasks.begin_shutdown();
self.request_close().await;
let shutdown_result = self.close_stream_task(Duration::from_secs(2)).await;
if let Some(control) = &self.socket_control {
control.deregister();
}
self.out_rx = None;
match shutdown_result {
Ok(()) => anyhow::bail!("Authentication failed: {e}"),
Err(shutdown_error) => anyhow::bail!(
"Authentication failed: {e}; handler shutdown failed: {shutdown_error}"
),
}
}
rollback.disarm();
Ok(())
}
/// Authenticates the WebSocket session with OKX.
async fn authenticate(&self) -> Result<(), Error> {
let credential = self.credential.as_ref().ok_or_else(|| {
Error::Io(std::io::Error::other(
"API credentials not available to authenticate",
))
})?;
let rx = self.auth_tracker.begin();View on GitHub (pinned to 18893faf8b)
Solutions
- Fix the underlying credential problem first (see the auth failure: key/secret/passphrase, clock sync, permissions).
- Investigate the appended `shutdown_error` — usually a handler task that already exited or a shutdown timeout.
- After a failed rollback, recreate the client instance rather than reusing it, since internal state (socket control, out_rx) was reset.
- Ensure connect/disconnect calls are serialized (await each fully) to avoid racing handler teardown.
Example fix
// before: reusing a client whose teardown half-failed client.connect().await?; // Authentication failed ... shutdown failed // after: rebuild after auth-fixing config change let client = OKXWebSocketClient::new(key, secret, passphrase, ...).await?; client.connect().await?;
Defensive patterns
Strategy: try-catch
Try / catch
match client.connect().await {
Err(e) if e.to_string().starts_with("Authentication failed") && e.to_string().contains("shutdown failed") => {
log::error!("auth + rollback both failed; rebuild the client: {e}");
client = build_new_client()?;
}
other => other?,
} Prevention
- Fix the credential problem first — the shutdown error is secondary.
- Recreate the client instance after this error; rollback state may be dirty.
- Avoid concurrent connect/disconnect racing that makes teardown time out.
- Increase awareness of the 2s shutdown windows; ensure the runtime is responsive.
When it happens
Trigger: Same as the plain auth failure ([1038]) — failed OKX login during `connect()` with credentials — combined with the cleanup path (`begin_shutdown`/`close_stream_task`) returning an error, e.g. because the handler task was already dead or timed out.
Common situations: Invalid credentials plus a racing handler-task crash; shutdown timeout (2s) exceeded while the socket is wedged; calling connect during runtime teardown where both auth and cleanup fail.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- errors.join("; ")
- Authentication failed: {e}
- failed to finish Binance Futures data command tasks: {e}
- Binance Futures data teardown failed: {}
- Binance Futures shutdown failed: {}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/54ef38bd921a6687.
Report an issue: GitHub.