{"record":{"id":"5961c0f22cc26737","repo":"jdx/mise","slug":"cannot-capture-non-file","errorCode":null,"errorMessage":"cannot capture non-file {}","messagePattern":"cannot capture non-file (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/shadow.rs","lineNumber":435,"sourceCode":"                    (\"160000\", crate::git::Git::new(&live).current_sha()?)\n                } else if meta.is_file() {\n                    #[cfg(unix)]\n                    let executable = {\n                        use std::os::unix::fs::PermissionsExt;\n                        meta.permissions().mode() & 0o100 != 0\n                    };\n                    #[cfg(not(unix))]\n                    let executable = false;\n                    let bytes = crate::agecrypt::read_bounded(\n                        std::fs::File::open(&live)?,\n                        crate::agecrypt::MAX_PLAINTEXT_BYTES,\n                    )?;\n                    (\n                        if executable { \"100755\" } else { \"100644\" },\n                        self.hash_blob(&bytes)?,\n                    )\n                } else {\n                    bail!(\"cannot capture non-file {}\", display_path(&live));\n                };\n                Ok(Overlay {\n                    path: rel\n                        .to_str()\n                        .ok_or_else(|| eyre::eyre!(\"non-UTF-8 tracked path\"))?\n                        .replace('\\\\', \"/\"),\n                    object: Some((mode.into(), oid)),\n                })\n            })();\n            match captured {\n                Ok(overlay) => overlays.push(overlay),\n                Err(error) => omitted.push(super::store::PathReason {\n                    path: display_path(&live),\n                    reason: format!(\"unreadable: {error:#}\"),\n                }),\n            }\n        }\n        self.compose(&self.empty_object(\"tree\")?, &overlays)","sourceCodeStart":417,"sourceCodeEnd":453,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/history/shadow.rs#L417-L453","documentation":"The non-encrypted capture path (tree_for_root via capture) hashes each live tracked path as a git blob, which requires a regular file. If a tracked path is not a regular file at capture time (directory, dangling symlink, special file), the snapshot cannot represent it and capture bails naming the path.","triggerScenarios":"capture (via tree_for_root) walks a tracked root and a tracked path resolves to a non-regular file when it attempts to read and hash its bytes.","commonSituations":"A path previously tracked as a file was replaced by a directory; a symlink's target was removed; a FIFO/socket appeared at a tracked path; filesystem race where the file was deleted between the walk and the read.","solutions":["Check the reported path with `ls -la` and remove or fix the non-file entry","Restore a deleted symlink target or delete the dangling symlink","Update the tracked-path configuration to reference actual files, then re-run capture"],"exampleFix":"// before: dangling symlink at tracked path\n~/.config/app/settings.json -> /mnt/usb/settings.json (missing)\n\n// after: real file present\n~/.config/app/settings.json (regular file)","handlingStrategy":"validation","validationCode":"// Rust: stat all tracked paths before calling capture\nfor p in &tracked {\n    let m = std::fs::symlink_metadata(p)\n        .with_context(|| format!(\"tracked path missing: {}\", p.display()))?;\n    anyhow::ensure!(m.is_file(), \"tracked path is not a file: {}\", p.display());\n}","typeGuard":"fn tracked_is_file(p: &std::path::Path) -> bool {\n    std::fs::symlink_metadata(p).map(|m| m.is_file()).unwrap_or(false)\n}","tryCatchPattern":"if let Err(e) = capture(&roots) {\n    if e.to_string().starts_with(\"cannot capture non-file\") {\n        eprintln!(\"snapshot skipped: {e}; fix the path and re-run\");\n    } else { return Err(e); }\n}","preventionTips":["Keep tracked paths pointed at regular files, not directories or FIFOs","Restore or remove dangling symlinks promptly","Expect races: re-run capture if a file was deleted mid-walk"],"tags":["filesystem","capture","snapshot"],"backgroundTag":"incompatible-source-type","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}