{"record":{"id":"ce0566842a303cb0","repo":"astrid-runtime/astrid","slug":"legacy-state-source-is-an-active-mount","errorCode":null,"errorMessage":"legacy state source is an active mount: {}","messagePattern":"legacy state source is an active mount: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-core/src/dirs_layout_retirement.rs","lineNumber":248,"sourceCode":"    root_device: u64,\n    metadata: &std::fs::Metadata,\n) -> io::Result<()> {\n    #[cfg(unix)]\n    {\n        if legacy_tree_device(metadata) != root_device {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                format!(\n                    \"legacy state source crosses a filesystem boundary: {}\",\n                    path.display()\n                ),\n            ));\n        }\n    }\n    #[cfg(not(unix))]\n    let _ = (root_device, metadata);\n    if is_active_mountpoint(path)? {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidData,\n            format!(\"legacy state source is an active mount: {}\", path.display()),\n        ));\n    }\n    Ok(())\n}\n\n#[cfg(target_os = \"linux\")]\npub(super) fn is_active_mountpoint(path: &Path) -> io::Result<bool> {\n    let canonical = std::fs::canonicalize(path)?;\n    let mountinfo = std::fs::read_to_string(\"/proc/self/mountinfo\")?;\n    Ok(mountinfo.lines().any(|line| {\n        let Some(mountpoint) = line.split_whitespace().nth(4) else {\n            return false;\n        };\n        decode_mountinfo_path(mountpoint).is_some_and(|mountpoint| mountpoint == canonical)\n    }))\n}","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-core/src/dirs_layout_retirement.rs#L230-L266","documentation":"ensure_legacy_tree_boundary rejects a legacy tree root that is itself an active mountpoint (checked via is_active_mountpoint). Deleting a mounted directory would either fail or, worse, let the library descend through the mount; retirement therefore refuses with InvalidData.","triggerScenarios":"retire_legacy_source_tree is called while the legacy source path (or, combined with 1205, any entry) is an active mountpoint — e.g. a volume is mounted exactly at the legacy state dir.","commonSituations":"Container runtime still has a volume mounted at the data path; systemd automount/tmpfs unit active; admin mounted a new disk at the old state location before migration.","solutions":["Unmount the mountpoint: umount <path> (or stop the systemd mount unit / container holding it), then retry retirement.","Move any data you need off the mounted volume first, since the legacy tree being retired should be empty or disposable.","If a service keeps re-mounting it, disable the mount unit or stop the workload before retiring."],"exampleFix":"// before\nmount | grep legacy  -> /dev/sdb1 on /data/legacy\n// after\numount /data/legacy","handlingStrategy":"validation","validationCode":"fn assert_not_mountpoint(p: &Path) -> io::Result<()> {\n    let parent_dev = std::fs::metadata(p.parent().unwrap())?.dev(); // unix\n    let dev = std::fs::metadata(p)?.dev();\n    if dev != parent_dev {\n        return Err(io::Error::new(io::ErrorKind::InvalidData, \"active mountpoint\"));\n    }\n    Ok(())\n}","typeGuard":"fn is_mountpoint(p: &Path) -> bool {\n    match (std::fs::metadata(p), p.parent().and_then(|q| std::fs::metadata(q).ok())) {\n        (Ok(c), Some(par)) => c.dev() != par.dev(),\n        _ => false,\n    }\n}","tryCatchPattern":"match retire_legacy_source_tree(&path, dev) {\n    Err(e) if e.to_string().contains(\"active mount\") => { /* umount + stop mount units, retry */ }\n    other => other?,\n}","preventionTips":["Check /proc/mounts or `mountpoint <path>` before retirement","Disable systemd automount units targeting state paths","Ensure containers are stopped and volumes detached first"],"tags":["rust","mount","filesystem"],"backgroundTag":"filesystem-boundary-crossing","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"}