{"record":{"id":"8058b4b94b92ac33","repo":"astrid-runtime/astrid","slug":"insufficient-free-space-for-layout-migration-need","errorCode":null,"errorMessage":"insufficient free space for layout migration: need {required} bytes, have {available} bytes","messagePattern":"insufficient free space for layout migration: need (.+?) bytes, have (.+?) bytes","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/astrid-core/src/dirs_layout.rs","lineNumber":489,"sourceCode":")]\nfn reject_automatic_windows_layout_one() -> io::Result<()> {\n    Ok(())\n}\n\n#[cfg(not(target_family = \"wasm\"))]\nfn ensure_migration_capacity(target: &Path, source_bytes: u64) -> io::Result<()> {\n    let available = fs2::available_space(target)?;\n    ensure_available_migration_capacity(available, source_bytes)\n}\n\n#[cfg(not(target_family = \"wasm\"))]\nfn ensure_available_migration_capacity(available: u64, source_bytes: u64) -> io::Result<()> {\n    let required = source_bytes\n        .checked_mul(2)\n        .and_then(|bytes| bytes.checked_add(LAYOUT_MIGRATION_HEADROOM_BYTES))\n        .ok_or_else(|| io::Error::other(\"layout migration capacity requirement overflow\"))?;\n    if available < required {\n        return Err(io::Error::new(\n            io::ErrorKind::StorageFull,\n            format!(\n                \"insufficient free space for layout migration: need {required} bytes, have {available} bytes\"\n            ),\n        ));\n    }\n    Ok(())\n}\n\n#[cfg(target_family = \"wasm\")]\nfn ensure_migration_capacity(_target: &Path, _source_bytes: u64) -> io::Result<()> {\n    Err(io::Error::new(\n        io::ErrorKind::Unsupported,\n        \"layout migration capacity probing is unavailable in a WebAssembly guest\",\n    ))\n}\n\nfn atomic_write(path: &Path, bytes: &[u8]) -> io::Result<()> {","sourceCodeStart":471,"sourceCodeEnd":507,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-core/src/dirs_layout.rs#L471-L507","documentation":"ensure_available_migration_capacity (via ensure_migration_capacity) requires the target filesystem to hold at least 2× the legacy source size plus a 64 MiB headroom constant before a layout migration may begin; this guarantees both the copy and the not-yet-retired source fit. When available space is below that requirement it returns io::ErrorKind::StorageFull with the exact needed vs. available byte counts. An overflowing requirement (source_bytes near u64::MAX) is rejected separately as 'capacity requirement overflow'.","triggerScenarios":"Calling begin_layout_v2_migration (which calls ensure_migration_capacity on var/) when the filesystem hosting the Astrid home has less than 2×state.db/cow size + 64 MiB free. Also triggered directly by tests feeding crafted available/source values.","commonSituations":"Running a migration on a small or nearly full disk or volume quota; large legacy state.db on a container with a tight overlay filesystem; shared hosting with aggressive disk quotas.","solutions":["Free space on the filesystem hosting the Astrid home (need ≥ 2× source size + 64 MiB — the error message states the exact requirement)","Move the Astrid home to a volume with sufficient free space before migrating","Shrink or prune the legacy source data (old state.db/cow content) if legitimately obsolete, lowering the required amount","Check for and raise disk quotas or container storage limits that artificially cap available space"],"exampleFix":"// before: 1 GB free, migration needs 2.1 GB\nhome.begin_layout_v2_migration(&target)?; // StorageFull: need 2201170432 bytes, have 1073741824\n// after: free or provision enough space\n// df -h /var/lib/astrid  -> ensure >= 2*source + 64MiB\nhome.begin_layout_v2_migration(&target)?; // proceeds","handlingStrategy":"validation","validationCode":"let available = fs2::available_space(home.var_dir())?;\nlet required = source_bytes * 2 + 64 * 1024 * 1024; // mirror the library rule\nif available < required {\n    return Err(anyhow!(\"need {required} bytes free, have {available}\"));\n}","typeGuard":"fn has_headroom(available: u64, source_bytes: u64) -> bool {\n    source_bytes.checked_mul(2)\n        .and_then(|b| b.checked_add(64 * 1024 * 1024))\n        .map(|req| available >= req)\n        .unwrap_or(false)\n}","tryCatchPattern":"match home.begin_layout_v2_migration(&target) {\n    Err(e) if e.kind() == std::io::ErrorKind::StorageFull => {\n        // free space (message shows exact need/have), then retry once\n    },\n    r => r?,\n}","preventionTips":["Monitor free space on the home volume and alert well below 2× source + 64 MiB","Run migrations on freshly provisioned or pruned disks, not near-full ones","Check container/quota storage limits before upgrading large homes","Clean obsolete legacy state.db/cow content before migrating to shrink the requirement"],"tags":["io","disk-space","migration","storage-full"],"backgroundTag":"file-size-limit-exceeded","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}