jdx/mise · warning

cannot capture non-file

Error message

cannot capture non-file {}

What it means

`tree_for_root`, called during snapshot capture, hashes each tracked file into the scratch git tree. Symlinks, directories (gitlinks), and regular files are handled; any other entry type reported by `symlink_metadata` reaches this bail. Unlike the capture of regular tracked files (which records omissions as warnings), this error path aborts building the overlay for that file and it is recorded as omitted with this reason.

Solutions

  1. Refine tracked globs to exclude sockets/FIFOs/device nodes on those paths.
  2. Check the entry with `stat`; only regular files, directories, and symlinks can be captured.
  3. Re-run capture if the path was mid-replacement — a transient race can yield a non-file type.
  4. Point tracking at the regular file itself rather than a directory wildcard that sweeps in special files.

Example fix

// before
files = ["~/**"]
// after
files = ["~/**", "!~/.run/**", "!~/**/*.sock", "!~/**/pipe*"]
Defensive patterns

Strategy: validation

Validate before calling

let meta = std::fs::symlink_metadata(&live)?;
let ok = meta.is_file() || meta.is_dir() || meta.file_type().is_symlink();
if !ok { eprintln!("cannot capture: {}", live.display()); }

Type guard

fn capturable_kind(meta: &std::fs::Metadata) -> Option<&'static str> {
    if meta.file_type().is_symlink() { Some("symlink") }
    else if meta.is_dir() { Some("dir") }
    else if meta.is_file() { Some("file") }
    else { None }
}

Prevention

When it happens

Trigger: A tracked path resolves to a non-file, non-directory, non-symlink entry (FIFO, socket, device node) or races to one between the walk and the stat in `tree_for_root` (called from `capture`).

Common situations: A tracked glob accidentally matches a socket or pipe (e.g. ~/.cache/** matching runtime sockets), a dev machine with odd device nodes under home, or a path being atomically replaced via a special file during capture.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/5961c0f22cc26737. Report an issue: GitHub.

Appendix: source

Thrown at src/system/history/shadow.rs:584

                    ("160000", crate::git::Git::new(&live).current_sha()?)
                } else if meta.is_file() {
                    #[cfg(unix)]
                    let executable = {
                        use std::os::unix::fs::PermissionsExt;
                        meta.permissions().mode() & 0o100 != 0
                    };
                    #[cfg(not(unix))]
                    let executable = false;
                    let bytes = crate::agecrypt::read_bounded(
                        std::fs::File::open(&live)?,
                        crate::agecrypt::MAX_PLAINTEXT_BYTES,
                    )?;
                    (
                        if executable { "100755" } else { "100644" },
                        self.hash_blob(&bytes)?,
                    )
                } else {
                    bail!("cannot capture non-file {}", display_path(&live));
                };
                Ok(Overlay {
                    path: rel
                        .to_str()
                        .ok_or_else(|| eyre::eyre!("non-UTF-8 tracked path"))?
                        .replace('\\', "/"),
                    object: Some((mode.into(), oid)),
                })
            })();
            match captured {
                Ok(overlay) => overlays.push(overlay),
                Err(error) => omitted.push(super::store::PathReason {
                    path: display_path(&live),
                    reason: format!("unreadable: {error:#}"),
                }),
            }
        }
        self.compose(&self.empty_object("tree")?, &overlays)

View on GitHub (pinned to 533346cc37)