nautechsystems/nautilus_trader · error
Architect AX orders WebSocket handler did not stop after…
Error message
Architect AX orders WebSocket handler did not stop after abort
What it means
Task-teardown failure in the Architect AX orders WebSocket client's close: after signaling abort and joining the handler task, the join outcome was Failed, meaning the background handler itself errored while shutting down rather than completing or being aborted cleanly.
Solutions
- Audit the orders handler loop for cancellation-token/abort handling around blocking awaits
- Add tokio::select! with the abort signal in long-running waits inside the handler
- Check for deadlock between command senders and the handler
- If reproducible, file a bug: a leaked handler task can hold the runtime or socket open
Defensive patterns
Strategy: try-catch
Try / catch
// Rust
if let Err(e) = orders.close().await {
tracing::error!("orders ws did not stop: {e}");
// consider aborting the underlying task handle or restarting the client
} Prevention
- Honor the abort/cancellation signal in all handler awaits via select!
- Bound every network wait with a timeout
- Avoid circular channel dependencies that can deadlock handler and command paths
- Add shutdown tests that simulate a hung exchange connection
When it happens
Trigger: Calling close() on the orders client while the orders handler is stuck (blocked await, non-cancelling loop, deadlock) and never reaches completion, failure, or abort-acknowledgement.
Common situations: Handler hung waiting on the exchange socket without honoring cancellation; command channel deadlock; very slow remote endpoint during shutdown.
Related errors
- Architect AX data WebSocket handler did not stop after abort
- Architect AX orders WebSocket handler failed
- Failed to terminate Hyperliquid data session tasks
- Hyperliquid WebSocket handler did not stop after abort
- Lighter WebSocket handler did not stop after abort
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/f5acd3f68ac08b47.
Report an issue: GitHub.
Appendix: source
Thrown at crates/adapters/architect_ax/src/websocket/orders/client.rs:754
tokio::time::sleep(Duration::from_millis(50)).await;
self.signal.store(true, Ordering::Release);
let outcome = self
.task_handle
.finish(Duration::from_secs(2), Duration::from_secs(2))
.await;
*self.reconnect_headers.lock() = None;
if let Some(control) = &self.socket_control {
control.deregister();
}
match outcome {
None | Some(TaskJoinOutcome::Completed(()) | TaskJoinOutcome::Aborted) => Ok(()),
Some(TaskJoinOutcome::Failed(error)) => Err(anyhow::anyhow!(
"Architect AX orders WebSocket handler failed: {error}"
)),
Some(TaskJoinOutcome::Incomplete) => Err(anyhow::anyhow!(
"Architect AX orders WebSocket handler did not stop after abort"
)),
}
}
async fn send_cmd(&self, cmd: HandlerCommand) -> AxOrdersWsResult<()> {
let guard = self.cmd_tx.read().await;
guard
.send(cmd)
.map_err(|e| AxOrdersWsClientError::ChannelError(e.to_string()))
}
}
impl Drop for AxOrdersWebSocketClient {
fn drop(&mut self) {
if Arc::strong_count(&self.task_handle) == 1 && !self.task_handle.is_empty() {
self.cancellation_token.load().cancel();
self.signal.store(true, Ordering::Release);View on GitHub (pinned to 18893faf8b)