nautechsystems/nautilus_trader · error · CommandSendError

CommandSendError: {details}

Error message

CommandSendError: {details}

What it means

This error is raised when the Databento live data client fails to send a HandlerCommand to its internal command channel (cmd_tx.send(cmd)). The channel send only fails if the receiver half has been dropped — meaning the command-processing loop inside the client is no longer running, so the client cannot accept any further commands (subscribe/unsubscribe etc.).

Source

Thrown at crates/adapters/databento/src/live.rs:318

        if self.is_closed {
            anyhow::bail!("Client already closed");
        }

        log::debug!("Closing client");

        if !self.cmd_tx.is_closed() {
            self.send_command(HandlerCommand::Close)?;
        }

        self.is_running = false;
        self.is_closed = true;

        Ok(())
    }

    fn send_command(&self, cmd: HandlerCommand) -> anyhow::Result<()> {
        self.cmd_tx.send(cmd).map_err(|e| {
            anyhow::Error::new(CommandSendError {
                details: e.to_string(),
            })
        })
    }
}

#[cfg(any(test, feature = "python"))]
pub(crate) fn is_command_send_error(error: &anyhow::Error) -> bool {
    error.is::<CommandSendError>()
}

#[derive(Debug)]
struct CommandSendError {
    details: String,
}

impl Display for CommandSendError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Verify the Databento live client is still running/connected before sending commands
  2. Check for premature termination of the client's command-processing loop (panics, early returns)
  3. Guard shutdown ordering: stop data handlers before dropping the client's command receiver
  4. Inspect logs for runtime shutdown occurring while commands were in flight
  5. Recreate the client if its internal loop has terminated
Defensive patterns

Strategy: try-catch

Validate before calling

// Guard: only send commands while the client loop is running
if !client.is_running() {
    return Err(anyhow!("Databento client stopped; cannot send command"));
}

Type guard

fn is_command_send_failure(err: &anyhow::Error) -> bool {
    err.to_string().starts_with("CommandSendError:")
}

Try / catch

if let Err(e) = client.send_command(cmd) {
    if is_command_send_failure(&e) {
        log::error!("Databento command loop gone; dropping client: {e}");
        // stop using this client; recreate if needed
    } else { return Err(e); }
}

Prevention

When it happens

Trigger: Calling send_command (via any public command path on the Databento live client) after the command receiver task has exited — e.g. the client's internal loop was stopped, the runtime is shutting down, or the client was disconnected.

Common situations: Issuing subscribe/unsubscribe commands after stopping the Databento live client; shutdown race where the node tears down while data handlers still send commands; a panic or early exit in the client's command loop.

Related errors


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