gitbutlerapp/gitbutler · error
Failed to determine target commit for hunk absorption due to
Error message
Failed to determine target commit for hunk absorption due to ambiguous dependencies in path: {} What it means
During absorption planning, ensure_target_commit() first tries to route a hunk through its dependency locks: find_top_most_lock() walks the stacks referenced by the locks and returns the first lock whose commit_id still exists in that stack's commits. If locks exist for the path but none point to a commit still present in current stack details (or a locked stack cannot be loaded), the dependency graph is unresolvable and absorption of that path aborts.
Source
Thrown at crates/but-api/src/legacy/absorb.rs:422
fn ensure_target_commit(
ctx: &mut Context,
candidate: &AbsorbCandidate,
locks: Option<&[HunkLock]>,
stack_details_cache: &mut HashMap<StackId, StackDetails>,
perm: &mut RepoExclusive,
) -> anyhow::Result<(
but_core::ref_metadata::StackId,
gix::ObjectId,
AbsorptionReason,
)> {
// Priority 1: Check if there's a dependency lock for this hunk
if let Some(locks) = locks {
if let Some(lock) = find_top_most_lock(locks, ctx, stack_details_cache) {
if let HunkLockTarget::Stack(stack_id) = lock.target {
return Ok((stack_id, lock.commit_id, AbsorptionReason::HunkDependency));
}
} else {
anyhow::bail!(
"Failed to determine target commit for hunk absorption due to ambiguous dependencies in path: {}",
candidate.hunk.path
);
}
}
// Priority 2: Use the candidate's stack ID if available
if let Some(stack_id) = candidate.stack_id {
let branch_ref = candidate.branch_ref.as_ref();
let stack_details = crate::legacy::workspace::stack_details(ctx, Some(stack_id))?;
if let Some(branch) = find_target_branch(&stack_details, branch_ref)
&& let Some(commit) = branch.commits.first()
{
return Ok((stack_id, commit.id, AbsorptionReason::StackAssignment));
}
// If there are no commits in the target branch, create a blank commit firstView on GitHub (pinned to 2497b8007a)
Solutions
- Delete or clear the stale hunk dependency locks for that path, then re-plan the absorption
- Re-establish the dependency by assigning the hunks to the intended stack/commit again after the rebase
- Absorb via AbsorptionTarget::Hunks with an explicit target, or assign the file to a stack so stack-id routing (priority 2) applies
- If the locked stack was deleted, remove its leftover locks too
Example fix
// before: plan while stale locks exist
let plan = absorption_plan(ctx, target)?; // fails: ambiguous dependencies
// after: prune locks whose commit no longer exists, then plan
for lock in hunk_locks_for_path(&path) {
if let HunkLockTarget::Stack(sid) = lock.target {
let details = workspace_stack_details(sid);
let alive = details.branch_details.iter()
.any(|b| b.commits.iter().any(|c| c.id == lock.commit_id));
if !alive { remove_hunk_lock(lock.id); }
}
}
let plan = absorption_plan(ctx, target)?; Defensive patterns
Strategy: try-catch
Validate before calling
for lock in locks_for_candidate_path {
if let HunkLockTarget::Stack(stack_id) = lock.target {
let details = stack_details(ctx, Some(stack_id))?;
let still_present = details.branch_details.iter()
.any(|b| b.commits.iter().any(|c| c.id == lock.commit_id));
if !still_present {
// clear or rewrite the stale lock before calling absorption_plan
}
}
} Type guard
fn locks_are_resolvable(
locks: &[HunkLock],
details_of: impl Fn(StackId) -> Option<&StackDetails>,
) -> bool {
locks.iter().any(|l| match l.target {
HunkLockTarget::Stack(sid) => details_of(sid)
.map(|d| {
d.branch_details.iter().any(|b| b.commits.iter().any(|c| c.id == l.commit_id))
})
.unwrap_or(false),
_ => true,
})
} Try / catch
match absorption_plan(ctx, target) {
Err(err) if err.to_string().contains("ambiguous dependencies") => {
// surface the conflicting locks for the path and offer to clear them
}
other => other,
} Prevention
- After rebasing or squashing a stack, refresh or clear hunk locks created against the old commits
- Do not hold lock commit ids across workspace rewrites
- Re-plan absorption immediately after editing dependencies rather than later
When it happens
Trigger: Hunk dependency locks reference commit ids that disappeared because the target stack was rebased, squashed, or amended after the lock was written; locks point at commits that were absorbed away; locks target stacks that were deleted; stack_details() fails for a locked stack id.
Common situations: Absorbing a hunk after editing or reordering the very commits it depended on; a graph rebase rewrote the workspace leaving stale HunkLock commit ids; locks persisted across a project import or restore.
Related errors
- No uncommitted changes found for the selected files
- Stack has no branches
- Failed to create blank commit in stack: {stack_id:?}
- Failed to create blank commit in leftmost stack
- Unable to determine target commit for unassigned change: {}
AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17).
Data as JSON: /api/errors/8b634d687408d920.
Report an issue: GitHub.