gitbutlerapp/gitbutler · error · but_error::Code
Validation
Validation
Error message
Commit {commit_id} is not conflicted What it means
but-api's conflict-resolution request builder refuses commits that carry no conflict data: but_core::Commit::conflicted_tree_ids() returned None, so the commit has no base/ours/theirs tree triple and is not one of GitButler's conflicted workspace commits. The error carries the Validation code — the request itself was inconsistent, not an IO or git failure. Note the doc comment: conflicts that exist but cannot be spliced (side deletions, binary, oversized files) go to 'manual' instead; only fully non-conflicted commits fail here.
Source
Thrown at crates/but-api/src/resolve/context.rs:134
}
#[cfg(feature = "export-schema")]
but_schemars::register_sdk_type!(ManualConflict);
/// Re-merge the conflict trees of `commit_id` and extract all conflict hunks.
///
/// Conflicts with no marker block to splice a resolution into — side deletions,
/// non-blob entries, binary or oversized files — are reported in `manual`
/// rather than failing the request, so the rest of the commit stays workable.
pub fn build_request(
repo: &gix::Repository,
commit_id: gix::ObjectId,
) -> anyhow::Result<ResolutionRequest> {
use gix::prelude::ObjectIdExt as _;
let commit = but_core::Commit::from_id(commit_id.attach(repo))?;
let Some((base, ours, theirs)) = commit.conflicted_tree_ids()? else {
bail!(
anyhow::anyhow!(Code::Validation)
.context(format!("Commit {commit_id} is not conflicted"))
);
};
let commit_message = but_core::commit::strip_conflict_markers(commit.message.as_ref())
.to_str_lossy()
.into_owned();
let parent_message = commit
.parents
.first()
.and_then(|parent_id| but_core::Commit::from_id(parent_id.attach(repo)).ok())
.map(|parent| commit_title(&parent));
let (base, ours, theirs) = (base.detach(), ours.detach(), theirs.detach());
let repo = repo.clone().for_tree_diffing()?;
// Merge without favoring a side to reproduce the actual conflicts, and
// force diff3-style markers with the sentinel labels so every hunk carriesView on GitHub (pinned to 2497b8007a)
Solutions
- Verify conflicted-ness first: re-read the commit and require conflicted_tree_ids() to be Some.
- Refresh the commit id from current workspace state instead of reusing a cached one.
- If conflicts were already resolved, route to the normal apply flow rather than resolution.
- Map Code::Validation to a user-facing 'nothing to resolve' response instead of a hard error.
Example fix
// before
let request = build_request(&repo, commit_id)?;
// after
let commit = but_core::Commit::from_id(commit_id.attach(&repo))?;
anyhow::ensure!(
commit.conflicted_tree_ids()?.is_some(),
"commit {commit_id} has no conflicts to resolve"
);
let request = build_request(&repo, commit_id)?; Defensive patterns
Strategy: validation
Validate before calling
let commit = but_core::Commit::from_id(commit_id.attach(&repo))?;
if commit.conflicted_tree_ids()?.is_none() {
anyhow::bail!("commit {commit_id} has no conflicts to resolve");
} Try / catch
match build_request(&repo, commit_id) {
Err(err) if err.chain().any(|c| c.to_string().contains("is not conflicted")) => {
refresh_workspace_state(&ctx)?; // id may be stale
build_request(&repo, refreshed_commit_id)
}
r => r,
}? Prevention
- Derive 'is conflicted' from the same commit object the resolve flow will use.
- Disable resolve UI as soon as resolutions are written back.
- Treat stale SHAs after rebase/snapshot as a signal to refresh state, not to retry blindly.
When it happens
Trigger: Calling build_request (crates/but-api/src/resolve/context.rs:118) with a plain commit, an already-resolved workspace commit, or a stale commit id — e.g. after a rebase/snapshot produced a new commit underneath the caller.
Common situations: UI retrying the resolve flow after the user already saved resolutions; commit ids cached from a previous workspace state; scripts driving the resolve API against arbitrary SHAs.
Related errors
- No uncommitted changes found for the selected files
- Failed to determine target commit for hunk absorption due to
- Stack has no branches
- Failed to create blank commit in stack: {stack_id:?}
- Failed to create blank commit in leftmost stack
AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17).
Data as JSON: /api/errors/5b82c1be647c7a22.
Report an issue: GitHub.