nautechsystems/nautilus_trader · info · TransportError

initial WebSocket connection cancelled

Error message

initial WebSocket connection cancelled

What it means

This error is returned when an initial WebSocket connection attempt is cancelled, typically because the caller dropped the connect future or a cancellation token fired while the first connection was still being established. The library surfaces the cancellation as an io::Error with ErrorKind::Interrupted wrapped in TransportError so callers can distinguish deliberate cancellation from genuine connect failures. It is not a network fault; the handshake never completed because the operation was aborted.

Source

Thrown at crates/network/src/websocket/client.rs:1006

        biased;
        () = cancellation_token.cancelled() => Err(initial_connect_cancelled()),
        result = attempt => result,
    }
}

fn initial_connect_retry_error(error: RetryError) -> TransportError {
    let kind = match error {
        RetryError::Canceled => return initial_connect_cancelled(),
        RetryError::InvalidConfiguration { .. } => std::io::ErrorKind::InvalidInput,
        RetryError::OperationTimeout { .. } | RetryError::ElapsedBudgetExceeded { .. } => {
            std::io::ErrorKind::TimedOut
        }
    };
    TransportError::Io(std::io::Error::new(kind, error))
}

fn initial_connect_cancelled() -> TransportError {
    TransportError::Io(std::io::Error::new(
        std::io::ErrorKind::Interrupted,
        "initial WebSocket connection cancelled",
    ))
}

// Debug when we asked to disconnect (Disconnect/Closed), else Warn for a peer close
fn read_termination_log_level(connection_state: &AtomicU8) -> log::Level {
    let mode = ConnectionMode::from_atomic(connection_state);
    if mode.is_disconnect() || mode.is_closed() {
        log::Level::Debug
    } else {
        log::Level::Warn
    }
}

#[cfg(test)]
mod connection_error_tests {
    use std::io;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check whether your code (or a timeout wrapper) is aborting the connect future prematurely and extend the connect timeout if the abort is unintentional
  2. Treat ErrorKind::Interrupted as benign shutdown and skip retry logic for it
  3. If cancellation is intended, ensure shutdown paths handle this error quietly instead of logging it as a failure
  4. Verify the CancellationToken is not dropped or cancelled while startup still needs the connection

Example fix

// before
let conn = tokio::spawn(client.connect()); // aborted on shutdown -> cancelled
// after
let conn = tokio::select! {
    res = client.connect() => res?,
    _ = shutdown_token.cancelled() => return Ok(()), // handle cancellation explicitly
};
Defensive patterns

Strategy: try-catch

Validate before calling

// Check cancellation state before connecting
if cancel_token.is_cancelled() { /* skip connect */ }

Type guard

fn is_cancelled(e: &TransportError) -> bool {
    matches!(e, TransportError::Io(io) if io.kind() == std::io::ErrorKind::Interrupted)
}

Try / catch

match client.connect().await {
    Err(e) if is_cancelled(&e) => log::debug!("connect cancelled, shutting down"),
    Err(e) => { /* retry or surface */ }
    Ok(c) => { /* proceed */ }
}

Prevention

When it happens

Trigger: Calling WebSocketClient::connect and dropping the returned future or cancelling it via the CancellationToken before the handshake completes; task shutdown/timeout wrappers aborting initial_connect; initial_connect_retry_error propagating a cancelled retry loop.

Common situations: Graceful shutdown during app startup; a supervisor timing out slow cold-start connects and aborting the task; user navigation closing a client mid-connect; retry loop exhausted by cancellation rather than failure.

Related errors


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