GitoxideLabs/gitoxide · info · anyhow::Error
Cancelled by user
Error message
Cancelled by user
What it means
The `gix odb statistics` command supports cancellation: when the user signals interruption (Ctrl-C) while iterating all objects, `gix::interrupt::Iter` short-circuits and the code raises `anyhow::anyhow!("Cancelled by user")`. It is a deliberate user-interrupt error, not a library fault.
Solutions
- Don't send SIGINT if you need the complete statistics output
- Re-run without interruption; the operation is read-only and safe to repeat
- Handle this message specially in scripts to distinguish user abort from failure
Defensive patterns
Strategy: try-catch
Try / catch
match cmd_output {
Err(e) if e.to_string().contains("Cancelled by user") => info!("user aborted statistics"),
Err(e) => error!("statistics failed: {e}"),
Ok(stats) => /* ... */,
} Prevention
- Avoid sending SIGINT to long-running gix commands in scripts
- Use gix::interrupt::init_handler only once per process
- Treat this message as a control-flow signal, not a failure
When it happens
Trigger: Running `gix odb statistics` (gitoxide-core `repository::odb::statistics`) and sending SIGINT / pressing Ctrl-C while the loose or packed object scan is in progress.
Common situations: Users aborting long-running object counts on huge repositories; automated scripts sending signals on timeout.
Related errors
- Cannot run without any task to perform on the repositories
- interrupted by user
- At least one operation failed
- No commits to process
- Refusing to checkout index into existing directory
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/99cd156f19e39744.
Report an issue: GitHub.
Appendix: source
Thrown at gitoxide-core/src/repository/odb.rs:174
type Error = anyhow::Error;
fn feed(&mut self, items: Self::Input) -> Result<Self::FeedProduce, Self::Error> {
for (id, item) in items? {
self.stats.consume(item);
if let Some(ids) = self.stats.ids.as_mut() {
ids.push(id);
}
}
Ok(())
}
fn finalize(mut self) -> Result<Self::Output, Self::Error> {
self.stats.total_objects = self.stats.loose_objects + self.stats.packed_objects;
Ok(self.stats)
}
}
let cancelled = || anyhow::anyhow!("Cancelled by user");
let object_ids = repo.objects.iter()?.filter_map(Result::ok);
let chunk_size = 1_000;
let mut stats = if gix::parallel::num_threads(thread_limit) > 1 {
gix::parallel::in_parallel(
gix::interrupt::Iter::new(
gix::features::iter::Chunks {
inner: object_ids,
size: chunk_size,
},
cancelled,
),
thread_limit,
{
let objects = repo.objects.clone();
move |_| (objects.clone().into_inner(), counter)
},
|ids, (handle, counter)| {
let ids = ids?;View on GitHub (pinned to e73179060b)