{"record":{"id":"ada3c77f59f3aa62","repo":"GitoxideLabs/gitoxide","slug":"prepared-splits-have-an-editor","errorCode":null,"errorMessage":"prepared splits have an editor","messagePattern":"prepared splits have an editor","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-tix/src/command.rs","lineNumber":681,"sourceCode":"        }\n        if !seen.insert(path.clone()) {\n            continue;\n        }\n        let change = changes\n            .paths\n            .iter()\n            .find(|change| change.path == path)\n            .with_context(|| format!(\"path {display:?} is not changed by HEAD\"))?;\n        selected.push(change.clone());\n    }\n    Ok(Some(selected))\n}\n\nfn split(repository: gix::Repository, graph: &crate::history::HistoryGraph, args: Split) -> Result<()> {\n    let repository_path = repository.git_dir().to_owned();\n    let bare = repository.is_bare();\n    let mut prepared = crate::edit::split::prepare(repository, args.todo)?;\n    let editor = prepared.editor.take().expect(\"prepared splits have an editor\");\n    let Some(edited) = crate::edit::edit_document_without_terminal(\n        editor,\n        &prepared.document,\n        &format!(\"tix-split-{}.md\", std::process::id()),\n    )?\n    else {\n        println!(\"no split performed: no input was provided\");\n        return Ok(());\n    };\n    let mut repository = crate::open_repository(&repository_path, bare, false)\n        .context(\"could not reopen repository after editing split\")?;\n    repository.object_cache_size(None);\n    let outcome = crate::edit::split::apply_reporting(repository, graph, prepared, &edited, |_| {})?;\n    let output_repository =\n        crate::open_repository(&repository_path, bare, false).context(\"could not reopen repository after splitting\")?;\n    let selected = outcome.selected.context(\"splitting did not produce a selection\")?;\n    println!(\"{}\", crate::change_id::display(&output_repository, selected, 7)?);\n    print_ref_rewrites(&output_repository, &outcome.ref_rewrites)?;","sourceCodeStart":663,"sourceCodeEnd":699,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-tix/src/command.rs#L663-L699","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlet editor = prepared.editor.take().expect(\"prepared splits have an editor\");\n// after\nlet editor = prepared.editor.take().ok_or_else(|| {\n    anyhow::anyhow!(\"split preparation did not provide an editor; check EDITOR/GIT_EDITOR settings\")\n})?;","handlingStrategy":"validation","validationCode":"let editor = match prepared.editor.take() {\n    Some(editor) => editor,\n    None => anyhow::bail!(\"split preparation produced no editor; cannot open the split document\"),\n};","typeGuard":"fn has_editor(prepared: &crate::edit::split::Prepared) -> bool {\n    prepared.editor.is_some()\n}","tryCatchPattern":"match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| run_split(repository, graph, args))) {\n    Ok(result) => result,\n    Err(_panic) => anyhow::bail!(\"tix split panicked: prepared split lacked an editor (library bug)\"),\n}","preventionTips":["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"],"tags":["rust","panic","internal-invariant","editor"],"backgroundTag":"internal-invariant-violation","analyzedSha":"e73179060badf27222d790981fac3f84c1830a7e","analyzedAt":"2026-09-08T11:26:50.865Z","contentChangedAt":"2026-09-08T11:26:50.865Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}