nautechsystems/nautilus_trader · error
Execution client is not started
Error message
Execution client is not started
What it means
query_account requires the execution client to be in the started state before it reads wallet balances and generates an AccountState. If core.is_started() is false — the client was constructed but never initialized/connected, or was stopped/degraded — the command is rejected. This prevents reporting balances from an uninitialized wallet/signer.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:5812
);
Ok(())
}
fn batch_cancel_orders(&self, cmd: BatchCancelOrders) -> anyhow::Result<()> {
for cancel in cmd.cancels {
self.cancel_order(cancel)?;
}
Ok(())
}
fn query_account(&self, cmd: QueryAccount) -> anyhow::Result<()> {
anyhow::ensure!(
cmd.account_id == self.core.account_id,
"Query account ID {} does not match client account ID {}",
cmd.account_id,
self.core.account_id
);
anyhow::ensure!(self.core.is_started(), "Execution client is not started");
let balances = self.wallet_balance.lock().as_account_balances()?;
self.generate_account_state(
balances,
vec![],
true,
get_atomic_clock_realtime().get_time_ns(),
None,
)
}
fn query_order(&self, cmd: QueryOrder) -> anyhow::Result<()> {
log::warn!(
"Order queries are not supported on the blockchain execution client; cannot query {}",
cmd.client_order_id
);
Ok(())
}View on GitHub (pinned to 18893faf8b)
Solutions
- Ensure the client is fully started/connected before issuing QueryAccount — wait for the started/initialized lifecycle event
- Call the client's connect/start path (which acquires the signer and wallet balances) if it was never started
- Reconnect or restart the client if it was stopped, then re-issue the query
- Gate downstream actors so they only query after the execution client reports readiness
Example fix
// before
client.query_account(cmd)?; // may run before start
// after
if client.core.is_started() {
client.query_account(cmd)?;
} else {
client.connect().await?;
client.query_account(cmd)?;
} Defensive patterns
Strategy: type-guard
Validate before calling
// gate queries on client readiness
if !client.is_started() {
return Err(anyhow::anyhow!("defer query: execution client not started"));
} Type guard
fn can_query(client: &ExecutionClient) -> bool {
client.core.is_started()
} Try / catch
match client.query_account(cmd) {
Err(e) if e.to_string().contains("not started") => {
// wait/retry until lifecycle reports started
wait_for_started(&client, Duration::from_secs(30)).await?;
client.query_account(cmd)
}
other => other,
} Prevention
- Subscribe to the client's started/initialized lifecycle event before issuing any queries
- Order startup: connect the execution client before starting actors that query balances
- After disconnect or fault, re-issue queries only after a successful reconnect
- Add readiness checks to scheduled balance polling jobs
When it happens
Trigger: Calling query_account (or emitting a QueryAccount on the bus) before connect()/initialize has completed, after disconnect/stop, or while the client is in a degraded/reconnecting state.
Common situations: An actor issues a balance query during startup before the execution client finished connecting; the client dropped its connection and stopped; a query is replayed after a restart; lifecycle wiring starts consumers before the client is fully initialized.
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
- Cannot connect while previous WebSocket handler task is stil
- Already running
- Cannot set cache database while node is running, set it befo
- Cannot add actor while node is running, add actors before ru
- Cannot add strategy while node is running, add strategies be
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/923a599ce8a68430.
Report an issue: GitHub.