GitoxideLabs/gitoxide · warning

Cancelled by user

Error message

Cancelled by user

What it means

In the `hours` command's `estimate`, while walking a commit's ancestors the inner loop checks `gix::interrupt::is_triggered()` after each iteration and bails with this message so a long-running history walk can be cancelled cleanly by SIGINT/Ctrl-C.

Solutions

  1. Expected on interruption — simply re-run `gix hours` when ready.
  2. Narrow the analysis (smaller repo range, fewer repos) so runs complete faster.
  3. Avoid sending SIGINT during the walk; use progress output to gauge remaining time.
  4. In scripts, treat this error as a cancellation status rather than a bug.
Defensive patterns

Strategy: try-catch

Try / catch

match res {
    Err(e) if e.to_string() == "Cancelled by user" => {
        eprintln!("hours estimate cancelled by SIGINT");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Sending SIGINT (Ctrl-C) while `estimate` is traversing commit ancestors via `commit_id.ancestors(&repo.objects)`; the check fires at the top of the next `while let Some(c) = commit_iter.next()` iteration.

Common situations: A developer running `gix hours` on a huge repository (tens of thousands of commits) decides to cancel it; a CI pipeline cancellation sends SIGINT mid-walk.

Related errors


AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08). Data as JSON: /api/errors/26ec05252f9071d5. Report an issue: GitHub.

Appendix: source

Thrown at gitoxide-core/src/hours/mod.rs:227

                        repo.clone(),
                        stats_counters.clone().expect("counters are set"),
                    );
                    (Some(tx), threads)
                }
            } else {
                Default::default()
            };

            let mut commit_idx = 0_u32;
            let mut skipped_merge_commits = 0;
            const CHUNK_SIZE: usize = 50;
            let mut chunk = Vec::with_capacity(CHUNK_SIZE);
            let mut commit_iter = commit_id.ancestors(&repo.objects);
            let mut is_shallow = false;
            while let Some(c) = commit_iter.next() {
                progress.inc();
                if gix::interrupt::is_triggered() {
                    bail!("Cancelled by user");
                }
                match c {
                    Ok(c) => {
                        tx.send((commit_idx, commit_iter.commit_data().to_owned())).ok();
                        let tree_delta_info = tx_tree_id.as_ref().and_then(|tx| {
                            let mut parents = c.parent_ids.into_iter();
                            parents
                                .next()
                                .map(|first_parent| (tx, Some(first_parent), c.id.to_owned()))
                                .filter(|_| {
                                    if parents.next().is_some() {
                                        skipped_merge_commits += 1;
                                        false
                                    } else {
                                        true
                                    }
                                })
                        });

View on GitHub (pinned to e73179060b)