Hmbown/CodeWhale · error · io::Error

snapshot path is not a regular file

Error message

snapshot path is not a regular file

What it means

snapshot_contains_regular_file runs `git cat-file -p <rev>:<path>` (via entry.stdout) against the snapshot repo and requires the mode line to be `100644 blob` or `100755 blob`. If the snapshot entry exists but is not a regular blob (e.g. a symlink `120000` or gitlink `160000` recorded in the snapshot commit), this InvalidInput error fires — the restore path only supports regular files.

Solutions

  1. Exclude the path from restore; only regular-file snapshot entries can be restored through this API.
  2. Convert the symlink/submodule in the workspace to a regular file and take a fresh snapshot.
  3. Restore the path manually with git commands if the old snapshot entry is needed.
Defensive patterns

Strategy: type-guard

Validate before calling

fn is_regular_blob(mode_line: &[u8]) -> bool {
    mode_line.starts_with(b"100644 blob ")
        || mode_line.starts_with(b"100755 blob ")
}

Prevention

When it happens

Trigger: Calling path_differs_from_snapshot or restore_paths_checked for a path whose snapshot entry is a symlink or submodule (gitlink) rather than a normal blob.

Common situations: A symlink or submodule was committed into the snapshot before the regular-file restriction existed; restoring from a snapshot created when symlinks were allowed.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/540f6196fb63e201. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/snapshot/repo.rs:694

                "-z",
                id.as_str(),
                "--",
                rel.to_str()
                    .ok_or_else(|| io_other("restore path must be UTF-8"))?,
            ],
        )?;
        if !entry.status.success() {
            return Err(io_other(format!(
                "Failed to inspect snapshot file: {}",
                String::from_utf8_lossy(&entry.stderr).trim()
            )));
        }
        if entry.stdout.is_empty() {
            return Ok(false);
        }
        if !(entry.stdout.starts_with(b"100644 blob ") || entry.stdout.starts_with(b"100755 blob "))
        {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "snapshot path is not a regular file",
            ));
        }
        Ok(true)
    }

    /// Return whether `rel` differs between snapshot `id` and the current
    /// working tree.
    ///
    /// This is the single-path counterpart of
    /// [`Self::work_tree_matches_snapshot`]: it answers "would restoring just
    /// this file change anything?", which is what file-scoped revert
    /// cursoring needs. A path that exists in neither the snapshot nor the
    /// working tree does not differ.
    pub fn path_differs_from_snapshot(&self, id: &SnapshotId, rel: &Path) -> io::Result<bool> {
        let in_work = self.validate_restore_file(rel)?;
        let in_target = self.snapshot_contains_regular_file(id, rel)?;

View on GitHub (pinned to 73e0f67d83)