nautechsystems/nautilus_trader · error
submit first
Error message
submit first
What it means
Test panic from `.expect("submit first")` on the first `EventStoreWriter::submit`, which returns `SubmitError::Closed` (writer shut down, thread exited, or prior halt latched) or `SubmitError::HaltSignaled` (channel full longer than `halt_threshold`). Under madsim, thread/timing semantics differ, making writer-thread liveness the usual failure point.
Source
Thrown at crates/event_store/src/writer/mod.rs:1874
}
#[rstest]
fn record_snapshot_anchor_records_current_watermark_under_madsim() {
let (wrapper, shared) = SharedMemory::new();
shared
.lock()
.open_run(manifest("run-anchor"))
.expect("open");
let writer = EventStoreWriter::spawn(
Box::new(wrapper),
get_atomic_clock_static(),
noop_halt(),
WriterConfig::default(),
)
.expect("spawn");
writer.submit(entry_draft(10)).expect("submit first");
writer.submit(entry_draft(11)).expect("submit second");
let anchor = writer
.record_snapshot_anchor("cache://position-snapshots/P-1/0", "blake3:abc")
.expect("record anchor");
let backend = shared.lock();
assert_eq!(anchor.high_watermark, 2);
assert_eq!(
backend.latest_snapshot_anchor().expect("latest anchor"),
Some(anchor),
);
}
}
View on GitHub (pinned to 18893faf8b)
Solutions
- Confirm `spawn` succeeded on a backend with an open run before the first submit.
- Under madsim, ensure the writer thread can run (check madsim thread model compatibility of the batcher loop).
- Raise `halt_threshold` if simulated latency legitimately exceeds it.
- Inspect the `SubmitError` variant to distinguish `Closed` from `HaltSignaled`.
Example fix
// before
writer.submit(entry_draft(10)).expect("submit first");
// after
writer.submit(entry_draft(10))
.unwrap_or_else(|e| panic!("submit first failed: {e:?}")); Defensive patterns
Strategy: retry
Validate before calling
if halted.load(Ordering::Acquire) { return Err(anyhow!("writer halted")); } Type guard
fn is_closed(e: &SubmitError) -> bool { matches!(e, SubmitError::Closed) } Try / catch
if let Err(SubmitError::Closed) = writer.submit(draft) {
log::warn!("writer closed; re-spawn required before further submits");
} Prevention
- Spawn on a backend with an open run so the writer thread survives.
- Under madsim, validate thread/scheduling assumptions early with a smoke submit.
- Set halt_threshold above simulated commit latency.
When it happens
Trigger: Submitting immediately after spawn when the writer thread failed to start; a halt already latched from setup; the bounded channel never draining because the writer thread is dead, blocking until `halt_threshold`.
Common situations: madsim test runs where thread spawn/scheduling behaves differently; halt threshold set too low relative to simulated commit latency; backend without an open run killing the writer thread at startup.
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
- submit second
- submit
- record anchor
- Invalid config type for AxExecutionClientFactory. Expected A
- Instrument not found in cache: {symbol}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/f411e31424005808.
Report an issue: GitHub.