nautechsystems/nautilus_trader · error

second submit fits

Error message

second submit fits

What it means

Panic from `.expect("second submit fits")` in `record_snapshot_anchor_signals_halt_when_submit_stalls`. After the first entry is confirmed blocked inside the backend append, a second submit must still be accepted into the single-slot channel; an `Err` panics.

Source

Thrown at crates/event_store/src/writer/mod.rs:1565

                max_batch_entries: 1,
                max_batch_latency: Duration::from_secs(30),
                halt_threshold,
            },
        )
        .expect("spawn");

        writer.submit(entry_draft(10)).expect("first submit fits");
        let mut waited = Duration::ZERO;
        while appends_seen.load(Ordering::SeqCst) == 0 && waited < Duration::from_secs(1) {
            std::thread::sleep(Duration::from_millis(2));
            waited += Duration::from_millis(2);
        }
        assert_eq!(
            appends_seen.load(Ordering::SeqCst),
            1,
            "writer must be blocked inside the first backend append",
        );
        writer.submit(entry_draft(11)).expect("second submit fits");

        let err = writer
            .record_snapshot_anchor("cache://position-snapshots/P-1/0", "blake3:abc")
            .expect_err("snapshot anchor submit must time out");
        let post_halt = writer
            .submit(entry_draft(12))
            .expect_err("post-halt submit");

        let (lock, cvar) = &*gate;
        *lock.lock() = true;
        cvar.notify_all();

        match err {
            EventStoreError::Backend(msg) => {
                assert!(
                    msg.contains("snapshot anchor submit stalled"),
                    "msg was: {msg}"
                );

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Print the `SubmitError` variant to identify Full/Closed/HaltSignaled.
  2. Confirm the first entry truly left the channel (the test asserts `appends_seen == 1` just before).
  3. Check halt logic has not fired — the gate is still closed and threshold is 50ms.
  4. Fix channel slot accounting so an in-backend (dequeue) entry frees its channel slot.

Example fix

// before
writer.submit(entry_draft(11)).expect("second submit fits");
// after
writer.submit(entry_draft(11)).unwrap_or_else(|e| panic!("second submit rejected: {e:?}"));
Defensive patterns

Strategy: try-catch

Validate before calling

// wait until the in-flight entry left the channel before submitting again
while writer.pending() >= capacity { sleep(1ms); }

Try / catch

writer.submit(d).unwrap_or_else(|e| panic!("second submit rejected: {e:?}"));

Prevention

When it happens

Trigger: `writer.submit(entry_draft(11))` returns `Err` when the channel slot should be free (the first entry left the channel and is blocked in append) — capacity accounting bug, premature halt/closed state, or the writer failing fast on backpressure.

Common situations: Channel capacity counted as occupied while an entry is being processed in the backend, halt logic firing before `halt_threshold` (50ms) elapses, or `SubmitError::Closed` surfacing because the writer thread errored.

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/931cf5cdf8b80a3b. Report an issue: GitHub.