jesseduffield/lazygit · error

Expected exactly one fixup hash, found %d

Error message

Expected exactly one fixup hash, found %d

What it means

Companion check in moveFixupCommitDown: it counts todos with command Pick and the fixup commit's hash and requires exactly one. Zero means the fixup commit being moved is not in the todo file; two or more means duplicated pick entries for it. The strict count protects against moving the wrong entry onto the original commit.

Source

Thrown at pkg/utils/rebase_todo.go:263

}

func moveFixupCommitDown(todos []todo.Todo, originalHash string, fixupHash string, changeToFixup bool) ([]todo.Todo, error) {
	isOriginal := func(t todo.Todo) bool {
		return (t.Command == todo.Pick || t.Command == todo.Merge) && equalHash(t.Commit, originalHash)
	}

	isFixup := func(t todo.Todo) bool {
		return t.Command == todo.Pick && equalHash(t.Commit, fixupHash)
	}

	originalHashCount := lo.CountBy(todos, isOriginal)
	if originalHashCount != 1 {
		return nil, fmt.Errorf("Expected exactly one original hash, found %d", originalHashCount)
	}

	fixupHashCount := lo.CountBy(todos, isFixup)
	if fixupHashCount != 1 {
		return nil, fmt.Errorf("Expected exactly one fixup hash, found %d", fixupHashCount)
	}

	_, fixupIndex, _ := lo.FindIndexOf(todos, isFixup)
	_, originalIndex, _ := lo.FindIndexOf(todos, isOriginal)

	newTodos := MoveElement(todos, fixupIndex, originalIndex+1)

	if changeToFixup {
		newTodos[originalIndex+1].Command = todo.Fixup
	}

	return newTodos, nil
}

func RemoveUpdateRefsForCopiedBranch(fileName string, commentChar byte) error {
	todos, err := ReadRebaseTodoFile(fileName, commentChar)
	if err != nil {
		return err

View on GitHub (pinned to c477a2959b)

Solutions

  1. Verify the fixup commit still exists as a single 'pick <hash>' line in .git-rebase-todo
  2. Remove duplicate pick lines for that hash or restart the rebase if the file is inconsistent
  3. If 'found 0', the fixup was already applied — refresh lazygit before attempting the squash
Defensive patterns

Strategy: validation

Validate before calling

# sanity check before fixup: fixup hash picked exactly once
grep -cE "^pick ${FULL_HASH}" .git/rebase-merge/git-rebase-merge/git-rebase-todo 2>/dev/null || grep -cE "^pick ${FULL_HASH}" .git/rebase-merge/git-rebase-todo  # want exactly 1

Try / catch

Catch and branch on the count: 0 → fixup already applied, refresh and skip; 2+ → de-duplicate pick lines in the todo, then retry.

Prevention

When it happens

Trigger: Squashing a fixup during interactive rebase when the fixup commit is missing from .git-rebase-todo (already applied/dropped) or appears as multiple pick lines.

Common situations: Same class as the original-hash error: externally modified todo files, stale lazygit models after a conflict resolution step, duplicated picks after rebase continuations.

Related errors


AI-assisted analysis of jesseduffield/lazygit@c477a2959b (2026-08-15). Data as JSON: /api/errors/5e46c64df5792d45. Report an issue: GitHub.