nautechsystems/nautilus_trader · error

Authentication failed

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.

Solutions

  1. Fix the underlying credential problem first (see the auth failure: key/secret/passphrase, clock sync, permissions).
  2. Investigate the appended `shutdown_error` — usually a handler task that already exited or a shutdown timeout.
  3. After a failed rollback, recreate the client instance rather than reusing it, since internal state (socket control, out_rx) was reset.
  4. 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

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

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/54ef38bd921a6687. Report an issue: GitHub.

Appendix: 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)