nautechsystems/nautilus_trader · error

submit

Error message

submit

What it means

This is a test panic from `.expect("submit")` on `EventStoreWriter::submit`, which returns `SubmitError` on failure. The library returns `SubmitError::Closed` when the writer is shut down, the writer thread has exited, or a prior halt already fired (halt is terminal for the run), and `SubmitError::HaltSignaled` when the submit blocked longer than the configured `halt_threshold` due to backpressure. In this latency-window test, a stall past the 30s halt threshold or an unexpected writer shutdown panics.

Source

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

        // surface at close drain, masking the steady-state batching contract.
        let (halt, _) = captured_halt;
        let (wrapper, shared) = SharedMemory::new();
        shared.lock().open_run(manifest("run-time")).expect("open");

        let writer = EventStoreWriter::spawn(
            Box::new(wrapper),
            get_atomic_clock_static(),
            halt,
            WriterConfig {
                channel_capacity: 32,
                max_batch_entries: 100,
                max_batch_latency: Duration::from_millis(20),
                halt_threshold: Duration::from_secs(30),
            },
        )
        .expect("spawn");

        writer.submit(entry_draft(10)).expect("submit");

        // Wait long enough that the latency window has elapsed multiple times.
        let mut waited = Duration::ZERO;
        while writer.high_watermark() == 0 && waited < Duration::from_millis(500) {
            std::thread::sleep(Duration::from_millis(5));
            waited += Duration::from_millis(5);
        }
        assert_eq!(
            writer.high_watermark(),
            1,
            "latency window must commit a sub-batch entry before close",
        );

        let final_hwm = writer.close(run_ended_draft()).expect("close");
        assert_eq!(final_hwm, 2);
    }

    #[rstest]

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure the backend has an open run before `EventStoreWriter::spawn` and that `append_batch` can commit promptly.
  2. Increase `WriterConfig::halt_threshold` or `channel_capacity` if legitimate bursts cause backpressure stalls.
  3. Never call `submit` after a halt fired or after `close`; check `high_watermark()`/halt state first.
  4. Match on the returned `SubmitError` (`Closed` vs `HaltSignaled`) and log `stalled_for`/`threshold` to identify which path fired.

Example fix

// before
writer.submit(entry_draft(10)).expect("submit");
// after
match writer.submit(entry_draft(10)) {
    Ok(()) => {}
    Err(SubmitError::Closed) => panic!("writer closed/halted before submit"),
    Err(SubmitError::HaltSignaled { stalled_for, threshold }) => {
        panic!("submit stalled {stalled_for:?} > {threshold:?}")
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before submitting
if writer_halted.load(Ordering::Acquire) { return; }
assert!(backend_has_open_run, "open_run must precede writer spawn");

Type guard

fn is_halt_signaled(e: &SubmitError) -> bool { matches!(e, SubmitError::HaltSignaled { .. }) }

Try / catch

match writer.submit(draft) {
    Ok(()) => {}
    Err(SubmitError::Closed) => log::warn!("writer closed; dropping entry"),
    Err(SubmitError::HaltSignaled { stalled_for, threshold }) => {
        log::error!("submit stalled {stalled_for:?} > {threshold:?}; halting run");
    }
}

Prevention

When it happens

Trigger: Calling `submit` after the writer thread exited or a halt was signaled; the entry channel staying full past `WriterConfig::halt_threshold` (e.g. backend `append_batch` commits stall longer than 30s); calling submit after `close` or after another submit stalled.

Common situations: A slow or blocked backend making the bounded channel back up; reusing a writer after a halt was latched by an earlier stall; tests with artificially tiny `max_batch_latency`/`halt_threshold` configs; spawning without an open run so the writer thread dies immediately.

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