nautechsystems/nautilus_trader · error
first submit fits
Error message
first submit fits
What it means
EventStoreWriter::submit enqueues an entry draft onto the writer's channel. The expect at writer/mod.rs:1134 ('first submit fits') panics if the first submit returns Err. Since the test uses channel_capacity=1 with a gated backend, the very first submit should fit; failure means the channel was already full, the writer halted, or the writer was closed.
Source
Thrown at crates/event_store/src/writer/mod.rs:1134
Arc::clone(&gate),
Arc::clone(&appends_seen),
);
let halt_threshold = Duration::from_millis(50);
let config = WriterConfig {
channel_capacity: 1,
max_batch_entries: 1,
max_batch_latency: Duration::from_millis(1),
halt_threshold,
};
let clock = get_atomic_clock_static();
let boxed = Box::new(backend);
let writer = EventStoreWriter::spawn(boxed, clock, halt, config).expect("spawn");
// First submit fits in the channel; the writer thread takes it and blocks.
writer.submit(entry_draft(10)).expect("first submit fits");
// Wait long enough for the writer to dequeue and become blocked at the gate.
std::thread::sleep(Duration::from_millis(20));
// Second and third submits saturate the slot; the channel buffer holds one,
// the next one stalls past the halt threshold.
let _ = writer.submit(entry_draft(11));
let stalled = writer.submit(entry_draft(12)).expect_err("must stall");
match stalled {
SubmitError::HaltSignaled { .. } => {}
SubmitError::Closed => panic!("expected HaltSignaled, was Closed"),
}
let captured_reasons = captured.lock();
assert_eq!(
captured_reasons.len(),
1,
"halt callback must fire exactly once",View on GitHub (pinned to 18893faf8b)
Solutions
- Make sure this is genuinely the first submit on a freshly spawned writer
- Check captured halt reasons — if a HaltReason is present, the writer latched closed and all submits fail
- Do not drop or close the writer before the expected first submit
- If a stall is expected later, submit once and wait for the writer thread to dequeue before filling the channel
Example fix
// before
writer.submit(entry_draft(10)).expect("first submit fits");
// after
writer
.submit(entry_draft(10))
.unwrap_or_else(|e| panic!("first submit should fit, got {e:?}")); Defensive patterns
Strategy: try-catch
Validate before calling
let reasons = captured.lock();
assert!(reasons.is_empty(), "writer already halted: {:?}", *reasons);
drop(reasons); Type guard
fn writer_accepts_submits(halt_reasons: &[HaltReason]) -> bool {
halt_reasons.is_empty()
} Try / catch
match writer.submit(entry_draft(10)) {
Ok(()) => {}
Err(SubmitError::HaltSignaled { reason, .. }) => eprintln!("halted: {reason:?}"),
Err(SubmitError::Closed) => eprintln!("writer closed"),
} Prevention
- Submit the first entry before any backend gate or failure path is exercised
- Track halt state via the halt callback before submitting
- Never drop or close the writer before planned submits
When it happens
Trigger: Calling writer.submit(entry_draft(10)) as the first submit when: the channel slot is already occupied, the writer thread has already signaled a halt (latched Closed), or the writer was dropped/closed before this call.
Common situations: Tests for backpressure halts where a previous submit already saturated the capacity-1 channel; submit racing with an early halt from a backend failure (GatedDiskFailureBackend); submitting after dropping or closing the writer.
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
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/9eae22e40c11a58e.
Report an issue: GitHub.