gitbutlerapp/gitbutler · error

Cannot compute diff specs for worktree

Error message

Cannot compute diff specs for worktree `{name}`

What it means

Diff specs cannot be computed for a whole worktree or its uncommitted area: during id resolution a worktree's uncommitted area is already expanded into its individual files, and the worktree reference itself holds no changes. The builder therefore rejects both `CliId::Worktree` and `CliId::WorktreeUncommitted` ids.

Solutions

  1. Use ids of the worktree's individual files/hunks instead of the worktree id
  2. If worktree-source support is needed, construct the builder with `for_change_source` rather than the default main-worktree builder
  3. Operate from inside the worktree so its changes appear as the normal uncommitted area
Defensive patterns

Strategy: validation

Validate before calling

if matches!(id, CliId::Worktree{..} | CliId::WorktreeUncommitted{..}) {
    eprintln!("worktree ids are not a diff-spec source; use its file/hunk ids");
    return Ok(());
}

Type guard

fn is_worktree_id(id: &CliId) -> bool { matches!(id, CliId::Worktree{..} | CliId::WorktreeUncommitted{..}) }

Try / catch

match result { Err(e) if e.to_string().starts_with("Cannot compute diff specs for worktree") => { /* use file ids from the worktree */ }, other => other }

Prevention

When it happens

Trigger: Passing a worktree id or worktree-uncommitted id to an operation that calls `push_changes_from_id`; per the source comment, operations that do support worktree sources must construct the builder via `DiffSpecsBuilder::for_change_source` instead.

Common situations: Targeting a linked worktree with a command that only reads the main worktree; scripting against `but worktree`/status output and using the worktree id where a file or hunk id is required.

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 gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/4c4ca45298347785. Report an issue: GitHub.

Appendix: source

Thrown at crates/but/src/utils/diff_specs.rs:90

                anyhow::bail!("Cannot compute diff specs for branch `{}`", branch.name)
            }
            CliId::AnonymousSegment(segment) => {
                anyhow::bail!("{}", anonymous_segment_error(&segment.id))
            }
            CliId::Commit {
                commit:
                    CommitId {
                        commit_id,
                        change_id: _,
                    },
                id: _,
            } => self.push_changes_from_commit(*commit_id),
            CliId::Uncommitted { id: _ } => self.push_changes_from_uncommitted_area(),
            // A worktree's uncommitted area is expanded into its files during
            // resolution, so the builder only ever sees hunks that already come from
            // its own repo. The reference holds no changes at all.
            CliId::Worktree { name, .. } | CliId::WorktreeUncommitted { name, .. } => {
                anyhow::bail!("Cannot compute diff specs for worktree `{name}`")
            }
            CliId::Stack { .. } => {
                anyhow::bail!("Cannot compute diff specs for stacks")
            }
            CliId::CommittedHunk(_) => {
                anyhow::bail!("Cannot compute diff specs for committed hunks")
            }
        }
    }

    pub fn push_changes_from_uncommitted(
        &mut self,
        uncommitted: &UncommittedHunkOrFile,
    ) -> anyhow::Result<()> {
        // Specs are built against one checkout's repository, so a hunk from
        // another would silently address the wrong files. Operations that support
        // worktree sources validate the selection and construct the builder via
        // [`Self::for_change_source`]; the rest read the main worktree and refuse

View on GitHub (pinned to 58e5313667)