GitoxideLabs/gitoxide · info · anyhow::Error
Cancelled by user
Error message
Cancelled by user
What it means
During pack creation, the object-counting/writing pipeline is wrapped with gix::interrupt::Iter and uses a cancellation closure returning 'Cancelled by user'. When the process interrupt flag is set mid-pack (during traversal or object iteration), the iteration aborts with this message. It is intentional cooperative cancellation of a long-running pack write.
Solutions
- Expected behavior: re-run the pack creation command; partial output should be discarded.
- Handle this error as a clean-cancel in callers instead of reporting a fault.
- For long packs, avoid wrapping interrupt checks or run in an environment that won't signal (detached, nohup).
- If cancelled spuriously, ensure only one component initializes the interrupt handler and that flags are reset between runs.
Example fix
// before
let pack = pack::create(&repo, tips, None, &mut progress)?;
// after
let pack = match pack::create(&repo, tips, None, &mut progress) {
Err(err) if err.to_string() == "Cancelled by user" => return Ok(()),
other => other?,
}; Defensive patterns
Strategy: try-catch
Try / catch
match pack::create(&repo, tips, input, &mut progress) {
Err(err) if err.to_string() == "Cancelled by user" => return Ok(()),
other => other?,
} Prevention
- Run long pack writes in environments that won't send SIGINT (detached/nohup).
- Discard partial pack output on cancellation.
- Handle cancellation as expected control flow, not an error condition.
When it happens
Trigger: Calling gitoxide_core::pack::create (public entry) with an input tip iterator and pressing Ctrl-C during commit traversal or object emission; the interrupt-aware iterator yields the error produced by make_cancellation_err.
Common situations: User aborting a large pack write; CI sending SIGINT/SIGTERM on timeout; interrupt flag set earlier in the process reused here.
Related errors
- interrupted by user
- Cancelled by user
- Cannot use iter_v1() on index of type
- Cannot use iter_v2() on index of type
- if you see this the object database is correct as a delta…
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/e2f552d6beac9da3.
Report an issue: GitHub.
Appendix: source
Thrown at gitoxide-core/src/pack/create.rs:116
statistics,
pack_cache_size_in_bytes,
object_cache_size_in_bytes,
mut out,
}: Context<W>,
) -> anyhow::Result<()>
where
W: std::io::Write,
P: NestedProgress,
P::SubProgress: 'static,
{
type ObjectIdIter = dyn Iterator<Item = Result<ObjectId, Box<dyn std::error::Error + Send + Sync>>> + Send;
let repo = gix::discover(repository_path)?;
let pack_compression = repo.pack_compression()?;
let repo = repo.into_sync();
progress.init(Some(2), progress::steps());
let tips = tips.into_iter();
let make_cancellation_err = || anyhow!("Cancelled by user");
let (mut handle, mut input): (_, Box<ObjectIdIter>) = match input {
None => {
let mut progress = progress.add_child("traversing");
progress.init(None, progress::count("commits"));
let tips = tips
.map({
let easy = repo.to_thread_local();
move |tip| {
ObjectId::from_hex(&Vec::from_os_str_lossy(tip.as_ref())).or_else(|_| {
easy.find_reference(tip.as_ref())
.map_err(anyhow::Error::from)
.and_then(|r| r.into_fully_peeled_id().map(gix::Id::detach).map_err(Into::into))
})
}
})
.collect::<Result<Vec<_>, _>>()?;
let handle = repo.objects.into_shared_arc().to_cache_arc();
let iter = Box::new(View on GitHub (pinned to e73179060b)