nautechsystems/nautilus_trader · error
Client never started
Error message
Client never started
What it means
`close` requires the client to have been started (`is_running == true`). Calling close on a client that was constructed but never started is an invalid state transition, so it bails with this error rather than performing a no-op teardown.
Source
Thrown at crates/adapters/databento/src/live.rs:297
self.bars_timestamp_on_close,
self.reconnect_timeout_mins,
);
self.send_command(HandlerCommand::Start)?;
self.is_running = true;
Ok((feed_handler, msg_rx))
}
/// Closes the live client.
///
/// # Errors
///
/// Returns an error if the client was never started, is already closed, or cannot send
/// the close command to the feed handler.
pub fn close(&mut self) -> anyhow::Result<()> {
if !self.is_running {
anyhow::bail!("Client never started");
}
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(())
}
View on GitHub (pinned to 18893faf8b)
Solutions
- Only call close after a successful `start`; track client state before cleanup.
- Make cleanup idempotent: skip close when the client was never started or is not running.
- If start failed, drop the client instead of closing it.
- Guard cleanup loops with a started/running check per client.
Example fix
// before let mut client = DatabentoLive::new(...)?; client.close()?; // error: never started // after let mut client = DatabentoLive::new(...)?; client.start().await?; // ... later ... client.close()?;
Defensive patterns
Strategy: try-catch
Validate before calling
// Only close clients that were started
if client.is_running() {
client.close()?;
} Try / catch
// Tolerate never-started in bulk cleanup
for client in &mut clients {
if client.is_running() {
if let Err(e) = client.close() {
log::warn!("close failed: {e}");
}
}
} Prevention
- Track a started flag per client in your session/registry code
- On start failure, drop the client rather than calling close
- Make teardown loops conditional on running state
When it happens
Trigger: Calling `close` (or `py_close`) on a DatabentoLive client before `start` was ever called, or after a failed start left `is_running` false.
Common situations: Error-path cleanup code that unconditionally closes all clients, including ones that never started; shutdown handlers iterating a registry of clients regardless of state; calling close after a start that itself errored.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Client already closed
- Client already running
- No feed handler found for dataset: {dataset}
- Command receiver already taken
- Active execution intent {intent_id} was not found
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/e045a1f3b2356a0d.
Report an issue: GitHub.