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

  1. Make sure this is genuinely the first submit on a freshly spawned writer
  2. Check captured halt reasons — if a HaltReason is present, the writer latched closed and all submits fail
  3. Do not drop or close the writer before the expected first submit
  4. 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

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.