GitoxideLabs/gitoxide · error
prepared splits have an editor
Error message
prepared splits have an editor
What it means
This is a Rust `Option::expect` panic on `prepared.editor`, an internal invariant assertion in the `tix split` command. `crate::edit::split::prepare()` is written to always populate the optional editor handle (`gix::command::Prepare`) used to launch the user's editor for the split document; if it is `None`, the codebase's assumptions are broken. It is not a user-facing error — it panics because a developer error or regression made the editor unavailable.
Solutions
- Check the `split::prepare` implementation to confirm it always sets `editor`; fix any path that returns `Prepared` without an editor.
- If a no-editor mode is intentional, replace the `expect` with a proper match that returns a user-facing error or edits without launching an editor.
- Run `just test` / the split command tests to confirm prepare's contract before relying on it.
- Report the panic upstream with the exact command and environment that triggered it, since it indicates a bug in the prepare/editors pipeline.
Example fix
// before
let editor = prepared.editor.take().expect("prepared splits have an editor");
// after
let editor = prepared.editor.take().ok_or_else(|| {
anyhow::anyhow!("split preparation did not provide an editor; check EDITOR/GIT_EDITOR settings")
})?; Defensive patterns
Strategy: validation
Validate before calling
let editor = match prepared.editor.take() {
Some(editor) => editor,
None => anyhow::bail!("split preparation produced no editor; cannot open the split document"),
}; Type guard
fn has_editor(prepared: &crate::edit::split::Prepared) -> bool {
prepared.editor.is_some()
} Try / catch
match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| run_split(repository, graph, args))) {
Ok(result) => result,
Err(_panic) => anyhow::bail!("tix split panicked: prepared split lacked an editor (library bug)"),
} Prevention
- Assert the prepare contract in a unit test: prepare() must always yield editor.is_some()
- Never make editor spawning silently optional in prepare without updating all call sites
- Prefer ok_or_else over expect when an Option field could plausibly be conditional
When it happens
Trigger: Running `tix split` where `edit::split::prepare()` returned a `Prepared` struct whose `editor` field was `None`. This can only happen if the prepare implementation changed to conditionally spawn an editor (e.g. skipping editor setup when the document is empty, or when stdin/stdout are not a terminal) without updating this call site.
Common situations: Hitting this during development of gix-tix after refactoring `split::prepare` or its `prepare_inner` helpers; running in environments where editor spawning fails earlier in prepare, leaving the handle unset; using a modified/patched build where the editor is deliberately suppressed.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- prepared commits have an editor
- only value and unspecified are possible here
- parent-match assures this
- upper match already assured we only deal with blobs
- fixed size array with three items
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/ada3c77f59f3aa62.
Report an issue: GitHub.
Appendix: source
Thrown at gix-tix/src/command.rs:681
}
if !seen.insert(path.clone()) {
continue;
}
let change = changes
.paths
.iter()
.find(|change| change.path == path)
.with_context(|| format!("path {display:?} is not changed by HEAD"))?;
selected.push(change.clone());
}
Ok(Some(selected))
}
fn split(repository: gix::Repository, graph: &crate::history::HistoryGraph, args: Split) -> Result<()> {
let repository_path = repository.git_dir().to_owned();
let bare = repository.is_bare();
let mut prepared = crate::edit::split::prepare(repository, args.todo)?;
let editor = prepared.editor.take().expect("prepared splits have an editor");
let Some(edited) = crate::edit::edit_document_without_terminal(
editor,
&prepared.document,
&format!("tix-split-{}.md", std::process::id()),
)?
else {
println!("no split performed: no input was provided");
return Ok(());
};
let mut repository = crate::open_repository(&repository_path, bare, false)
.context("could not reopen repository after editing split")?;
repository.object_cache_size(None);
let outcome = crate::edit::split::apply_reporting(repository, graph, prepared, &edited, |_| {})?;
let output_repository =
crate::open_repository(&repository_path, bare, false).context("could not reopen repository after splitting")?;
let selected = outcome.selected.context("splitting did not produce a selection")?;
println!("{}", crate::change_id::display(&output_repository, selected, 7)?);
print_ref_rewrites(&output_repository, &outcome.ref_rewrites)?;View on GitHub (pinned to e73179060b)