nautechsystems/nautilus_trader · error
Flush command should not be drained
Error message
Flush command should not be drained
What it means
Companion to the Close panic: in `drain_buffer` (crates/infrastructure/src/redis/cache.rs), encountering `DatabaseOperation::Flush(_)` in the drained buffer panics with "Flush command should not be drained". Flush is a control/lifecycle command that the command processor must intercept; finding it in the drainable operation buffer indicates the internal separation between control commands and data operations broke.
Source
Thrown at crates/infrastructure/src/redis/cache.rs:870
log::error!("Null `payload` for `replace_list`");
}
}
DatabaseOperation::Delete => {
log::debug!(
"Processing DELETE for collection: {}, key: {}, payload: {:?}",
collection,
key,
msg.payload.as_ref().map(std::vec::Vec::len)
);
// `payload` can be `None` for a delete operation
if let Err(e) = delete(&mut pipe, collection, &key, msg.payload) {
log::error!("{e}");
} else {
has_pending_ops = true;
}
}
DatabaseOperation::Close => panic!("Close command should not be drained"),
DatabaseOperation::Flush(_) => panic!("Flush command should not be drained"),
}
}
flush_pending_pipeline(conn, &mut pipe, &mut has_pending_ops).await;
}
async fn flush_pending_pipeline(
conn: &mut ConnectionManager,
pipe: &mut Pipeline,
has_pending_ops: &mut bool,
) {
if !*has_pending_ops {
return;
}
if let Err(e) = pipe.query_async::<()>(conn).await {
log::error!("{e}");
}View on GitHub (pinned to 18893faf8b)
Solutions
- Route Flush through the dedicated control path (handle_command/process_commands match on Flush) and never push it into the drained buffer.
- Intercept Flush/Close variants before enqueueing database operations.
- Reproduce with RUST_BACKTRACE=1 to find the enqueue site and fix the routing.
Example fix
// before buffer_tx.send(DatabaseOperation::Flush(pattern)).await?; // lands in drained buffer // after // invoke the cache's flush command API so handle_command consumes it directly
Defensive patterns
Strategy: validation
Validate before calling
debug_assert!(!matches!(op, DatabaseOperation::Flush(_)), "Flush must go through the control path");
Try / catch
// guard enqueue sites: if is_control_op(&op) { control_tx.send(op).await?; } else { buffer_tx.send(op).await?; } Prevention
- Expose Flush only through the cache's command API, never through the op buffer.
- Avoid racing user-triggered flush with background buffer draining.
- Add an assertion/test that the drained stream contains only data operations.
When it happens
Trigger: A `DatabaseOperation::Flush` being enqueued into the operation buffer and then drained by `drain_buffer` (via `process_commands`, `handle_command`, or `flush_buffer`) instead of being handled as an explicit cache flush command.
Common situations: Calling cache flush concurrently with buffered writes so the Flush op lands in the queue; custom integrations enqueueing Flush into the data channel; version mismatches where Flush routing changed.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Close command should not be drained
- Redis config error: username supplied without password. Eith
- Order invariant violated: first event must be OrderInitializ
- Empty `payload` for `delete` '{key}'
- API key is valid UTF-8
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/99ea946c8faaf576.
Report an issue: GitHub.