gitbutlerapp/gitbutler · error
Invalid source: expected an uncommitted file or branch
Error message
Invalid source: expected an uncommitted file or branch
What it means
`but absorb` folds uncommitted changes into the commits they belong to. Its optional source must be an uncommitted file/hunk ID (absorb just that file) or a branch/lane ID (absorb everything assigned to that lane); no source absorbs everything uncommitted. This bail is the `_` catch-all of the AbsorptionTarget conversion: the resolved CliId was neither `UncommittedHunkOrFile` nor `Branch` (e.g. a commit or another entity kind reached the match).
Source
Thrown at crates/but/src/command/legacy/absorb.rs:89
})
.transpose()?;
let target = if let Some(source) = source {
match source {
CliId::UncommittedHunkOrFile(UncommittedHunkOrFile { hunks, .. }) => {
// Absorb this particular file
AbsorptionTarget::Hunks {
hunks: hunks.map(|id_and_hunk| id_and_hunk.hunk).into(),
}
}
CliId::Branch(branch) => {
// Absorb everything that is assigned to this lane
AbsorptionTarget::Branch {
branch_name: branch.name,
}
}
_ => {
anyhow::bail!("Invalid source: expected an uncommitted file or branch");
}
}
} else {
// Try to absorb everything uncommitted
Default::default()
};
// TODO: Ideally, there's a simpler way of getting the worktree changes without passing the context to it.
// At this time, the context is passed pretty deep into the function.
let absorption_plan =
but_api::legacy::absorb::absorption_plan_with_perm(ctx, target, guard.write_permission())?;
// Absorbing into a landed commit entangles the new change with an entire
// already-merged commit, which conflicts on the next `but pull`. Drop such
// plan entries and tell the user, instead of silently amending them.
let merged = MergedUpstream::from_ctx(ctx, allow_merged)?;
let Some((absorption_plan, skipped_merged)) =
drop_landed_absorptions(absorption_plan, &merged, out)?View on GitHub (pinned to caf1f223d3)
Solutions
- Run `but absorb` with no source to absorb all uncommitted changes.
- Pass an uncommitted-file ID or a branch/lane ID from `but status` (`but absorb 2a` for a file, `but absorb b1` for a lane).
- If calling absorb programmatically, filter IdMap results to `CliId::UncommittedHunkOrFile` or `CliId::Branch` before converting to AbsorptionTarget.
Example fix
# before but absorb 4z # 4z is a commit ID -> Invalid source: expected an uncommitted file or branch # after but absorb # absorb all uncommitted changes but absorb 2a # 2a = uncommitted file ID but absorb b1 # b1 = branch/lane ID
Defensive patterns
Strategy: validation
Validate before calling
# Verify the ID names an uncommitted file or a lane before absorbing
but status | grep -F '<id>' || { echo 'not an absorbable source'; exit 2; }
but absorb '<id>' Type guard
// For callers of the IdMap / but API: only these variants are absorbable sources
fn is_absorbable_source(clid: &CliId) -> bool {
matches!(clid, CliId::UncommittedHunkOrFile { .. } | CliId::Branch(_))
} Prevention
- Only pass IDs that `but status` lists under uncommitted files or lanes.
- Omit the source argument to absorb everything uncommitted.
- When scripting against the API, filter IdMap results to UncommittedHunkOrFile/Branch before converting to AbsorptionTarget.
When it happens
Trigger: A resolved CLI ID of an entity kind other than uncommitted file/hunks or branch (e.g. `CliId::Commit`) reaching the AbsorptionTarget match in crates/but/src/command/legacy/absorb.rs:89. Note the handler pre-filters sources at absorb.rs:56-59 and rejects bad selectors with a different message, so this arm fires when an unexpected CliId kind slips through (other callers, future variants).
Common situations: Passing a commit ID copied from `but status` to `but absorb`; scripts invoking the absorb handler with an unvalidated IdMap result; CLI versions drifting so new entity kinds are not covered by the match arms.
Related errors
- Failed to parse diff header
- BUG: It should not be possible to omit sources
- {} target value is required
- target kind is required when target value is provided
- Cannot compute diff specs for worktree `{name}`
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/7e7e22788871100c.
Report an issue: GitHub.