{"record":{"id":"db83bef8f63cc51b","repo":"nautechsystems/nautilus_trader","slug":"second-submit-must-be-buffered-by-the-clamped-capa","errorCode":null,"errorMessage":"second submit must be buffered by the clamped capacity","messagePattern":"second submit must be buffered by the clamped capacity","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/event_store/src/writer/mod.rs","lineNumber":1303,"sourceCode":"            std::thread::sleep(Duration::from_millis(5));\n            waited += Duration::from_millis(5);\n        }\n        assert_eq!(\n            appends_seen.load(Ordering::SeqCst),\n            1,\n            \"writer thread did not reach the gated append\",\n        );\n\n        // Release the gate before asserting so a regression fails instead of\n        // hanging the writer join.\n        let second_submit = writer.submit(entry_draft(11));\n\n        let (lock, cvar) = &*gate;\n        *lock.lock() = true;\n        cvar.notify_all();\n\n        let final_hwm = writer.close(run_ended_draft()).expect(\"close\");\n        second_submit.expect(\"second submit must be buffered by the clamped capacity\");\n        assert_eq!(final_hwm, 3);\n        assert!(captured.lock().is_empty());\n    }\n\n    #[rstest]\n    fn submit_after_writer_thread_halt_returns_closed(\n        captured_halt: (HaltCallback, Arc<Mutex<Vec<HaltReason>>>),\n    ) {\n        // A writer-thread halt latches the shared flag; post-halt submits must\n        // reject rather than be accepted and silently dropped.\n        let (halt, captured) = captured_halt;\n        let config = WriterConfig {\n            max_batch_entries: 1,\n            ..WriterConfig::default()\n        };\n\n        let writer = EventStoreWriter::spawn(\n            Box::new(DiskFailureBackend::default()),","sourceCodeStart":1285,"sourceCodeEnd":1321,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/event_store/src/writer/mod.rs#L1285-L1321","documentation":"A test panic from `.expect(\"second submit must be buffered by the clamped capacity\")` at crates/event_store/src/writer/mod.rs:1303. It fires when the deferred `submit(entry_draft(11))` result is `Err` — i.e. the writer rejected the submit instead of buffering it. The test asserts that when `channel_capacity: 0` is configured, the writer clamps it to a working capacity so the second submit is buffered rather than refused with `SubmitError::Closed` or `SubmitError::HaltSignaled`.","triggerScenarios":"Configuring `WriterConfig { channel_capacity: 0, .. }` while the writer thread is blocked inside a gated `append_batch`, then calling `writer.submit(...)`; if the capacity clamp regresses (submit rejected outright instead of buffered), the expect panics.","commonSituations":"Zero-capacity or under-provisioned channel configurations; CI runs of the `zero_channel_capacity_is_clamped_and_submit_buffers` rstest after a refactor of the submit retry loop or channel sizing.","solutions":["Fix the capacity clamp so `channel_capacity == 0` is clamped to at least 1 before the channel is created in `EventStoreWriter::spawn`.","Check the concrete `SubmitError` (replace expect with `unwrap_err`/`matches!`) to distinguish `Closed` (halt latched) from `HaltSignaled` (stall threshold too low).","Increase `halt_threshold` in the test config if the submit legitimately stalls because the gated backend holds `append_batch` too long.","Ensure the gate is released (`lock = true; cvar.notify_all()`) before the retry loop exhausts, so the buffered submit can be accepted."],"exampleFix":"// before\nsecond_submit.expect(\"second submit must be buffered by the clamped capacity\");\n// after\nsecond_submit\n    .expect(\"clamped capacity must buffer the second submit instead of rejecting it\");","handlingStrategy":"validation","validationCode":"// Validate config before spawn\nassert!(config.halt_threshold >= Duration::from_millis(100),\n    \"halt_threshold too small for gated-backend tests\");","typeGuard":"match second_submit {\n    Ok(()) => {},\n    Err(SubmitError::Closed) => eprintln!(\"halt latched; submit refused\"),\n    Err(SubmitError::HaltSignaled { .. }) => eprintln!(\"stall threshold tripped\"),\n}","tryCatchPattern":"second_submit.unwrap_or_else(|e| panic!(\"second submit rejected: {e:?}\"));","preventionTips":["Never assume channel_capacity: 0 is honored literally; rely on the documented clamp and test it explicitly.","Release gates before asserting deferred submits succeeded.","Set halt_threshold well above worst-case backend block time.","Inspect SubmitError variants rather than panicking on the first Err."],"tags":["rust","panic","backpressure","channel-capacity"],"backgroundTag":"internal-invariant-violation","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}