gitbutlerapp/gitbutler · error
no commit IDs provided for uncommit
Error message
no commit IDs provided for uncommit
What it means
commit_uncommit_only_with_perm refuses an empty subject_commit_ids list before touching the workspace: uncommit needs at least one commit id to rewrite/remove, so the guard bails immediately, before recording surfaced hunks or creating the Editor.
Source
Thrown at crates/but-api/src/commit/uncommit.rs:206
///
/// The commits are removed from branch history, but their changes are
/// **kept** — they surface as uncommitted workspace modifications. When
/// `assign_to` is set, newly surfaced hunks are assigned to that stack.
///
/// This contrasts with [`super::discard_commit::commit_discard()`], which
/// removes both the commit and its changes.
///
/// When `dry_run` is enabled, it returns a preview of the resulting workspace
/// state without materializing the rewrite.
pub fn commit_uncommit_only_with_perm(
ctx: &mut but_ctx::Context,
subject_commit_ids: Vec<gix::ObjectId>,
assign_to: Option<but_core::ref_metadata::StackId>,
dry_run: DryRun,
perm: &mut RepoExclusive,
) -> anyhow::Result<UncommitResult> {
if subject_commit_ids.is_empty() {
anyhow::bail!("no commit IDs provided for uncommit");
}
let context_lines = ctx.settings.context_lines;
let mut meta = ctx.meta()?;
let (repo, mut ws, mut db) = ctx.workspace_mut_and_db_mut_with_perm(perm)?;
let surfaced =
SurfacedHunks::record_before(assign_to, dry_run, &mut db, &repo, &ws, context_lines)?;
let editor = Editor::create(&mut ws, &mut meta, &repo, &mut db)?;
let mut rebase =
but_workspace::commit::discard_commits(editor, subject_commit_ids.iter().copied())
.with_context(|| {
format!(
"failed to uncommit commits: {}",
subject_commit_ids
.iter()
.map(|id| id.to_hex().to_string())View on GitHub (pinned to 2497b8007a)
Solutions
- Pass at least one commit id to uncommit.
- Guard the caller: skip or notify when the selection is empty instead of calling the API.
- Require a non-empty selection in the UI before enabling uncommit.
Example fix
// before
but_api::commit_uncommit_only_with_perm(ctx, vec![], assign_to, DryRun::No, perm)?;
// after
if !subject_commit_ids.is_empty() {
but_api::commit_uncommit_only_with_perm(ctx, subject_commit_ids, assign_to, DryRun::No, perm)?;
} Defensive patterns
Strategy: validation
Validate before calling
fn can_uncommit(subject_commit_ids: &[gix::ObjectId]) -> bool {
!subject_commit_ids.is_empty()
} Prevention
- Gate the uncommit action on a non-empty selection.
- Treat empty commit lists as no-ops in pipelines.
- Log when a filter produces zero commits so callers can skip early.
When it happens
Trigger: Calling the uncommit API (commit_uncommit_only_with_perm or its but-api wrapper) with an empty Vec of commit ids — empty UI selection, or a caller looping over a commit list that came back empty.
Common situations: Frontends not gating the uncommit button on selection; scripts filtering commits by message/path that match nothing.
Related errors
- No commits were provided to squash
- HTTP Error ${response.statusText}: ${text}
- Branch {branch_name} not found
- Failed to create pull request: {status} - {error_text}
AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17).
Data as JSON: /api/errors/079dcfc5c7071b42.
Report an issue: GitHub.