GitoxideLabs/gitoxide · warning

interrupted by user

Error message

interrupted by user

What it means

During `perform_run`, before each repository in the corpus is processed the engine checks `gix::interrupt::is_triggered()` (SIGINT/Ctrl-C flag). If an interrupt signal was received, it aborts the whole run with this bail so the process exits with a clear error instead of being killed mid-write.

Solutions

  1. This is expected on user interruption — no fix needed; re-run the command without sending a signal.
  2. If interruption happens unintentionally, check terminal/CI signal forwarding (e.g. CI cancellation, `timeout` commands).
  3. For long runs, restrict the corpus with a repo SQL suffix or fewer tasks so runs finish before you need to interrupt.
  4. Handle the resulting `anyhow` error gracefully in scripts by checking for the 'interrupted by user' message.
Defensive patterns

Strategy: try-catch

Try / catch

match res {
    Err(e) if e.to_string() == "interrupted by user" => {
        eprintln!("run cancelled; partial results kept");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Pressing Ctrl-C (or sending SIGINT) to the process while `Engine::perform_run` is iterating over corpus repositories, causing the `gix::interrupt` handler flag to be set before the next repo begins.

Common situations: A developer realizes a corpus run over hundreds of repos is taking too long and hits Ctrl-C; a CI job is cancelled and the harness sends SIGINT; a user interrupts after seeing bad progress output.

Related errors


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

Appendix: source

Thrown at gitoxide-core/src/corpus/engine.rs:118

                        repo_progress.inc();
                    }
                    repo_progress.info(format!("with {} tasks", tasks.len()));
                    for (_, task) in tasks {
                        repo_progress.info(format!("task '{}' ({})", task.description, task.short_name));
                    }
                    break 'tasks_loop;
                }
                let mut run_progress = repo_progress.add_child("set later");
                let (_guard, current_id) = corpus::trace::override_thread_subscriber(
                    db_path.as_str(),
                    self.state.trace_to_progress.then(|| repo_progress.add_child("trace")),
                    self.state.reverse_trace_lines,
                )?;

                let mut num_errors = 0;
                for repo in &repos {
                    if gix::interrupt::is_triggered() {
                        bail!("interrupted by user");
                    }
                    run_progress.set_name(format!(
                        "{}",
                        repo.path
                            .strip_prefix(corpus_path)
                            .expect("corpus contains repo")
                            .display()
                    ));

                    // TODO: wait for new release of `tracing-forest` to be able to provide run_id via span attributes
                    let mut run = Self::insert_run(&self.con, gitoxide_id, runner_id, *task_id, repo.id)?;
                    current_id.store(run.id, Ordering::SeqCst);
                    tracing::info_span!("run", run_id = run.id).in_scope(|| {
                        task.perform(
                            &mut run,
                            &repo.path,
                            &mut run_progress,
                            Some(threads),

View on GitHub (pinned to e73179060b)