{"record":{"id":"7f610d9f54fb425b","repo":"clockworklabs/SpacetimeDB","slug":"no-space-left-on-device-7f610d","errorCode":null,"errorMessage":"no space left on device","messagePattern":"no space left on device","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/dst/src/sim/commitlog.rs","lineNumber":463,"sourceCode":"        self.inner.seek(pos)\n    }\n}\n\nimpl SegmentLen for ReadOnlySegment {}\n\nfn next_page_multiple(size: u64) -> io::Result<u64> {\n    let page = PAGE_SIZE as u64;\n    let remainder = size % page;\n    if remainder == 0 {\n        return Ok(size);\n    }\n\n    size.checked_add(page - remainder)\n        .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, \"allocation size overflow\"))\n}\n\nfn enospc() -> io::Error {\n    io::Error::new(io::ErrorKind::StorageFull, \"no space left on device\")\n}\n\n#[cfg(test)]\nmod tests {\n    use std::io::{Read, Seek, Write};\n\n    use super::*;\n\n    fn segment() -> Segment {\n        Segment::from_shared(Arc::new(Mutex::new(u64::MAX)), Arc::new(RwLock::new(Storage::new())))\n    }\n\n    #[test]\n    fn write_overwrites_at_seek_position() {\n        let mut segment = segment();\n\n        segment.write_all(b\"abcdef\").unwrap();\n        segment.seek(io::SeekFrom::Start(2)).unwrap();","sourceCodeStart":445,"sourceCodeEnd":481,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/6dee26c6efc2856793e12b148a59742964f5d783/crates/dst/src/sim/commitlog.rs#L445-L481","documentation":"The in-memory commitlog models a device with a finite space budget: a shared u64 counter ('space') is decremented as segments grow their allocation. When Segment::write needs more pages than remain in the budget, it returns ErrorKind::StorageFull via enospc() with the classic ENOSPC message 'no space left on device'. This lets simulation tests exercise disk-full behavior deterministically (the test fixture at line ~470 constructs the repo with u64::MAX to disable the quota).","triggerScenarios":"Creating a Memory repo with a finite space budget and writing more bytes than budgeted across segments; growing several segments concurrently so the shared counter is exhausted; tests that deliberately size the budget to trigger the full-disk path.","commonSituations":"Simulation harnesses for the commitlog/durable-log layer: quota set smaller than the log the test produces; forgetting to raise the budget when a test's data volume grows; retention not removing old segments so the budget drains.","solutions":["Construct Memory with a larger space budget (u64::MAX disables the quota entirely) when disk-full is not the behavior under test","Remove/rotate old segments (remove_segment frees their budget share) before writing new ones","If testing the ENOSPC path intentionally, size the budget just below the write that should fail, and assert on ErrorKind::StorageFull"],"exampleFix":"// before\nlet repo = Memory::new(/* space */ 4096);\n// ... writes beyond 4 KiB -> StorageFull\n\n// after\nlet repo = Memory::new(u64::MAX); // quota disabled for this test\n// or: remove_segment(old_offset)?; before appending","handlingStrategy":"fallback","validationCode":"// If you expose the budget, pre-check headroom before a big append:\nfn headroom(space: &Mutex<u64>, allocated: u64, want: u64) -> bool {\n    *space.lock().unwrap() >= want.saturating_sub(allocated).next_multiple_of(4096)\n}","typeGuard":null,"tryCatchPattern":"match seg.write(buf) {\n    Err(ref e) if e.kind() == std::io::ErrorKind::StorageFull => {\n        repo.remove_segment(oldest_retired_offset)?; // free budget\n        seg.write(buf)? // retry after freeing\n    }\n    r => r?,\n}","preventionTips":["Size the Memory repo's space budget generously vs the data the test writes; u64::MAX disables the quota","Remove/rotate retired segments so the budget is reclaimed before appending","Assert on ErrorKind::StorageFull (not the message) when testing the full-disk path"],"tags":["commitlog","storage","rust","enospc","disk-full","simulation"],"backgroundTag":"enospc-out-of-space","analyzedSha":"6dee26c6efc2856793e12b148a59742964f5d783","analyzedAt":"2026-08-20T06:08:37.179Z","contentChangedAt":"2026-08-20T06:08:37.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}