GitoxideLabs/gitoxide · error

copy-insert requires a worktree

Error message

copy-insert requires a worktree

What it means

The paste-insert feature inserts a pasted commit into history, which requires a writable working tree to check out and modify files. When the application was started against a bare repository, `anyhow::ensure!` aborts the paste handler with this message.

Solutions

  1. Open the repository with an associated worktree (non-bare clone) before using paste-insert.
  2. Use a different editing action that works without a worktree (e.g. pure history rewrite APIs), if available.
  3. Check how the app was launched: pass a worktree checkout path, not the bare repo dir.

Example fix

// before
let action = (|| {
    anyhow::ensure!(!repository_is_bare, "copy-insert requires a worktree");
// after
if repository_is_bare {
    eprintln!("paste-insert unavailable in a bare repository");
    return Ok(Action::None);
}
let action = (|| {
    anyhow::ensure!(!repository_is_bare, "copy-insert requires a worktree");
Defensive patterns

Strategy: validation

Validate before calling

if repository_is_bare {
    eprintln!("paste-insert requires a non-bare repository with a worktree");
    return;
}

Type guard

fn has_worktree(repo: &gix::Repository) -> bool { repo.work_dir().is_some() }

Try / catch

match paste_action() {
    Err(e) if e.to_string().contains("requires a worktree") => show_unavailable_notice(),
    Err(e) => return Err(e),
    Ok(v) => v,
}

Prevention

When it happens

Trigger: Pasting (TerminalEvent::Paste) while `repository_is_bare` is true; the app's paste-insert path calls `open_repository`/`resolve_pasted_commit` only after this guard, so any paste action in a bare-repo session hits it.

Common situations: Running the TUI against `--bare` repos or `~/.git` style metadata dirs; remote-style repositories opened locally without a worktree; users expecting paste to work like a non-worktree commit amendment.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at gix-tix/src/lib.rs:2093

                                    distance += 1;
                                }
                                next => {
                                    pending_terminal_event = Some(next);
                                    break;
                                }
                            }
                        }
                    }
                    let Some(action) = mouse_scroll_action(kind, modifiers, distance, app.changes_focus.is_some())
                    else {
                        continue;
                    };
                    let repeats_history = app.changes_focus.is_none() && repeats_viewport(&action);
                    (Some(action), repeats_history, true, true)
                }
                TerminalEvent::Paste(pasted) => {
                    let action = (|| {
                        anyhow::ensure!(!repository_is_bare, "copy-insert requires a worktree");
                        let target = app
                            .paste_insert_target()
                            .context("copy-insert paste requires an editable history selection")?;
                        let repository = open_repository(&repository_path, repository_is_bare, false)
                            .context("could not open repository for pasted commit")?;
                        let source = resolve_pasted_commit(&repository, &pasted)?;
                        Ok::<_, anyhow::Error>(Action::PasteInsert { source, target })
                    })();
                    match action {
                        Ok(action) => (Some(action), false, false, false),
                        Err(err) => {
                            app.leave_attention(format!("paste: {err:#}"));
                            dirty = true;
                            urgent = true;
                            continue;
                        }
                    }
                }

View on GitHub (pinned to e73179060b)