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

  1. Pass at least one commit id to uncommit.
  2. Guard the caller: skip or notify when the selection is empty instead of calling the API.
  3. 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

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


AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17). Data as JSON: /api/errors/079dcfc5c7071b42. Report an issue: GitHub.