GitoxideLabs/gitoxide · error
a reference is placed more than once
Error message
a reference is placed more than once
What it means
Each reference name may be positioned (moved to a commit) at most once within a rebase todo. If the same ref appears in reference lines under two different fork/command sections, the parser cannot decide a single new target for it and bails.
Solutions
- Remove the duplicate reference line, keeping only the one in the desired section
- If the ref should not move at all, delete both lines and let tix keep it at its current position
- Reopen the todo to regenerate a clean template before re-editing
Example fix
// before ──fork abc1234── (main) ──fork def5678── (main) // after ──fork abc1234── (main) ──fork def5678── (no ref line for main)
Defensive patterns
Strategy: validation
Validate before calling
let mut seen = HashSet::new();
for name in ref_names_in_todo(edited) {
if !seen.insert(name.clone()) {
return Err(format!("ref {} appears more than once", name));
}
} Try / catch
if let Err(e) = parse(repo, edited) {
if e.to_string().contains("placed more than once") {
// highlight the duplicated ref line for the user
}
} Prevention
- Move a ref line instead of copying it
- Search the todo for the ref name before re-adding it
- Use one reference line per ref across all sections
When it happens
Trigger: `parse` bails when `ref_targets.insert(name, target)` returns Some — i.e. `parse_ref_line` yielded a ref whose name was already recorded for a different (or same) position. Happens when a user duplicates a `(refs/heads/...)` line across fork sections while editing the todo.
Common situations: Copy-pasting reference lines while rearranging sections; forgetting that moving a ref line relocates it (the original must be removed); template mistakes.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- a fork section contains no commits
- a fork target must be picked before it is used
- the rebase todo cannot select a checkout without a worktree
- the rebase todo contains more than one @ reference
- the rebase todo contains more than one @ command
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/daa433985208823f.
Report an issue: GitHub.
Appendix: source
Thrown at gix-tix/src/edit/todo.rs:900
)?;
cursor = Some(if let Some(index) = picked.get(&id) {
rebase::PlanParent::Step(*index)
} else if scope.contains(&id) {
anyhow::bail!("a fork target must be picked before it is used");
} else {
rebase::PlanParent::Existing(id)
});
sections += 1;
section_has_commit = false;
section_last_step = None;
continue;
}
if line.starts_with('(') && line.ends_with(')') {
let target = cursor.context("a reference line must follow a fork or command")?;
for (marked, value) in parse_ref_line(line)? {
let name = resolve_ref_name(repo, &mut state.expected_refs, value.as_bstr())?;
if ref_targets.insert(name.clone(), target).is_some() {
anyhow::bail!("a reference is placed more than once");
}
if marked {
if !state.checkout_allowed || repo.workdir().is_none() {
anyhow::bail!("the rebase todo cannot select a checkout without a worktree");
}
if explicit_checkout_reference.replace((name, target)).is_some() {
anyhow::bail!("the rebase todo contains more than one @ reference");
}
}
}
section_has_commit = true;
continue;
}
let (command, tail) = if let Some(line) = line.strip_prefix('`') {
let (command, tail) = line
.split_once('`')
.context("a Markdown todo command has no closing backtick")?;View on GitHub (pinned to e73179060b)