gitbutlerapp/gitbutler · error

Refusing to read Git metadata path

Error message

Refusing to read Git metadata path '{}'

What it means

read_worktree_file validates path components with gix and refuses any path that resolves into the .git directory (gix::validate::path::component::Error::DotGitDir). Reading Git metadata files through this API is not allowed.

Solutions

  1. Exclude .git (and nested git dirs) from the paths you request.
  2. Read Git metadata through dedicated git APIs (repo config, refs) instead of file reads.
  3. Filter directory listings before requesting file contents.

Example fix

// before
read_file_from_workspace(project, ".git/config")
// after
if path.components().any(|c| c.as_os_str() == ".git") { return Err(...); }
read_file_from_workspace(project, path)
Defensive patterns

Strategy: validation

Validate before calling

fn touches_git_dir(p: &Path) -> bool {
    p.components().any(|c| c.as_os_str() == ".git")
}
if touches_git_dir(path) { return Err("git metadata paths are not readable here"); }

Type guard

fn is_git_metadata(p: &Path) -> bool {
    p.components().any(|c| c.as_os_str() == ".git")
}

Try / catch

match result {
    Err(e) if e.to_string().contains("Refusing to read Git metadata path") => {
        // skip this path in listings
    }
    other => other,
}

Prevention

When it happens

Trigger: Calling read_worktree_file for a path inside .git (e.g. ".git/config", ".git/HEAD", ".git/objects/...") via get_workspace_file_from_source or read_file_from_workspace.

Common situations: A file watcher or UI listing the worktree includes .git contents and something tries to display them; tooling asking to read .git/COMMIT_EDITMSG through the workspace-file API.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/81fcf9afb859dbd7. Report an issue: GitHub.

Appendix: source

Thrown at crates/gitbutler-repo/src/commands.rs:393

                canonical_workdir.display()
            );
        }
    };

    // Refuse `.git` in every spelling an OS can map onto it (`.GIT`,
    // `GIT~1`, `.git.`). Runs before the stat: `.git` can be a file
    // (linked worktrees) and must be refused all the same.
    if relative_path.components().any(|component| {
        matches!(
            gix::validate::path::component(
                component.as_os_str().as_encoded_bytes().as_bstr(),
                None,
                Default::default(),
            ),
            Err(gix::validate::path::component::Error::DotGitDir)
        )
    }) {
        bail!(
            "Refusing to read Git metadata path '{}'",
            relative_path.display()
        );
    }

    let out = match path.symlink_metadata() {
        Ok(md) => {
            // Directories are exempt: their `FileInfo` placeholder carries no
            // content, and callers rely on getting it rather than an error.
            if !md.is_dir() {
                ensure_not_ignored(repo, &relative_path)?;
            }

            if md.is_file() {
                let content = std::fs::read(&path)?;
                FileInfo::from_content(&relative_path, &content)
            } else if md.is_symlink() {
                let content = std::fs::read_link(&path)?;

View on GitHub (pinned to 58e5313667)