{"record":{"id":"67a825776458ed1a","repo":"astrid-runtime/astrid","slug":"legacy-source-is-an-active-mount","errorCode":null,"errorMessage":"legacy source is an active mount: {}","messagePattern":"legacy source is an active mount: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-kernel/src/legacy_migration_barrier/host_fs.rs","lineNumber":267,"sourceCode":"            io::ErrorKind::AlreadyExists,\n            format!(\n                \"legacy source changed before retirement: {}\",\n                path.display()\n            ),\n        ));\n    }\n    let metadata = fs::symlink_metadata(path)?;\n    if !metadata.is_dir() {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidData,\n            format!(\n                \"legacy retirement root is not a directory: {}\",\n                path.display()\n            ),\n        ));\n    }\n    if active_mountpoint(path)? {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidData,\n            format!(\"legacy source is an active mount: {}\", path.display()),\n        ));\n    }\n    let device = device_id(&metadata);\n    for entry in fs::read_dir(path).map_err(io::Error::other)? {\n        let child = entry.map_err(io::Error::other)?.path();\n        if protected.iter().any(|candidate| candidate == &child) {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                format!(\n                    \"legacy component source reappeared during ordinary retirement: {}\",\n                    child.display()\n                ),\n            ));\n        }\n        let child_meta = fs::symlink_metadata(&child).map_err(io::Error::other)?;\n        if child_meta.file_type().is_symlink() || (!child_meta.is_file() && !child_meta.is_dir()) {","sourceCodeStart":249,"sourceCodeEnd":285,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/legacy_migration_barrier/host_fs.rs#L249-L285","documentation":"retire_tree refuses to delete a legacy source that is itself an active mount point, detected via /proc/self/mountinfo (Linux) or statfs filesystem-id comparison (macOS). Deleting a mounted directory would only clear the mountpoint while leaving the mounted data, so the operation aborts with InvalidData.","triggerScenarios":"retire_tree -> active_mountpoint(path) returns true because the legacy path is a bind mount, tmpfs, network mount, or (macOS) resides on a different filesystem than its parent. This check runs at the root and recursively at each child (children on a different device raise the sibling boundary error).","commonSituations":"Users bind-mounting or symlinking-via-mount legacy data from another volume into the old location; Docker/overlay or NFS mounts placed at the legacy path; macOS users whose home is on a different volume than the mount point's parent.","solutions":["Unmount the mount point (`umount <path>`) so the legacy path is an ordinary directory again, then rerun retirement.","Move the mount elsewhere; the legacy path must live on the same filesystem as its parent with no mount at or below it.","If the data genuinely lives on the other volume, migrate it physically into the legacy location (or update config) instead of mounting.","After unmounting, verify with `findmnt <path>` that nothing is mounted before retrying."],"exampleFix":"# before\nmount --bind /data/legacy ~/.astrid/legacy/db\n// after\numount ~/.astrid/legacy/db\nrsync -a /data/legacy/ ~/.astrid/legacy/db/   # physical copy, then migrate","handlingStrategy":"validation","validationCode":"// Linux: check the path is not a mount point before migrating\nfn is_mountpoint(path: &std::path::Path) -> std::io::Result<bool> {\n    let canon = std::fs::canonicalize(path)?;\n    let mi = std::fs::read_to_string(\"/proc/self/mountinfo\")?;\n    Ok(mi.lines().any(|l| l.split_whitespace().nth(4) == Some(canon.to_str().unwrap_or(\"\"))))\n}","typeGuard":null,"tryCatchPattern":"match retire_tree(path, &expected, &protected) {\n    Err(e) if e.to_string().contains(\"is an active mount\") => {\n        eprintln!(\"unmount {} before migration\", path.display());\n    }\n    other => other?,\n}","preventionTips":["Keep legacy data as plain directories on one filesystem — no bind mounts, tmpfs, or NFS at legacy paths","Run `findmnt --target <path>` as a pre-migration check","On macOS, ensure the home and its parent live on the same volume"],"tags":["filesystem","mount","migration","rust"],"backgroundTag":"unsupported-operation","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"}