gitbutlerapp/gitbutler · error

no commit IDs provided for discard

Error message

no commit IDs provided for discard

What it means

Discarding commits requires at least one commit ID to remove from branch history. The helper `unique_subject_commit_ids` deduplicates the caller-supplied list and bails if nothing remains. This guards downstream rebase machinery from running a pointless or destructive no-op operation.

Solutions

  1. Ensure the caller collects at least one commit ID before invoking discard
  2. Check the selection/argument list for emptiness in your UI or CLI layer and short-circuit with a user-facing message
  3. If IDs may contain duplicates, deduplicate is handled internally, but verify your source of IDs isn't returning an empty set due to a filtering bug

Example fix

// before
api.commit_discard_only(ctx, vec![])?;
// after
if commit_ids.is_empty() {
    eprintln!("Nothing selected to discard");
    return Ok(());
}
api.commit_discard_only(ctx, commit_ids)?;
Defensive patterns

Strategy: validation

Validate before calling

if commit_ids.is_empty() {
    return Err(anyhow::anyhow!("nothing selected to discard"));
}

Try / catch

match api.commit_discard_only(ctx, ids) {
    Err(e) if e.to_string().contains("no commit IDs provided") => warn_user("select commits first"),
    other => other?,
}

Prevention

When it happens

Trigger: Calling `commit_discard_only_with_perm` or `commit_discard_with_perm` with an empty `subject_commit_ids` vector (or a vector containing only duplicate IDs that dedupe to zero entries).

Common situations: UI layers passing an empty selection when the user confirms discard with nothing selected; CLI argument parsing producing an empty list; upstream filtering logic removing all IDs before the call.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/b6336bf02c0ec5c1. Report an issue: GitHub.

Appendix: source

Thrown at crates/but-api/src/commit/discard_commit.rs:19

use crate::WorkspaceState;
use but_api_macros::but_api;
use but_core::{DiffSpec, DryRun, sync::RepoExclusive};
use but_oplog::legacy::{OperationKind, SnapshotDetails, Trailer};
use but_rebase::graph_rebase::Editor;
use tracing::instrument;

use crate::commit::types::{CommitDiscardResult, MoveChangesResult};

fn unique_subject_commit_ids(
    subject_commit_ids: Vec<gix::ObjectId>,
) -> anyhow::Result<Vec<gix::ObjectId>> {
    let mut seen = gix::hashtable::HashSet::default();
    let subject_commit_ids = subject_commit_ids
        .into_iter()
        .filter(|commit_id| seen.insert(*commit_id))
        .collect::<Vec<_>>();
    if subject_commit_ids.is_empty() {
        anyhow::bail!("no commit IDs provided for discard");
    }
    Ok(subject_commit_ids)
}

/// Discard `subject_commit_ids`, removing them from branch history.
///
/// Unlike [`super::uncommit::commit_uncommit()`], the commits' changes are **not**
/// reassigned to the workspace — they are permanently removed from their branches.
///
/// When `dry_run` is enabled, the returned workspace previews the discard
/// without materializing the rebase.
/// See [`commit_discard_only_with_perm()`] for details.
#[but_api(try_from = crate::commit::json::CommitDiscardResult)]
pub fn commit_discard_only(
    ctx: &mut but_ctx::Context,
    subject_commit_ids: Vec<gix::ObjectId>,
    dry_run: DryRun,
) -> anyhow::Result<CommitDiscardResult> {

View on GitHub (pinned to 58e5313667)