jesseduffield/lazygit · error

index outside of range of commits

Error message

index outside of range of commits

What it means

BeginInteractiveRebaseForCommitRange validates that the `end` index fits the commits slice (len(commits)-1 < end) before building ChangeTodoActions for indexes start..end. An out-of-range end would panic on commits[commitIndex].Hash(), so this is a fail-fast guard against a stale or inconsistent commit list.

Source

Thrown at pkg/commands/git_commands/rebase.go:427

		if self.config.NeedsGpgSubprocessForCommit() {
			return errors.New(self.Tr.DisabledForGPG)
		}

		return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
			baseHashOrRoot:             getBaseHashOrRoot(commits, commitIndex),
			instruction:                daemon.NewInsertBreakInstruction(),
			keepCommitsThatBecomeEmpty: keepCommitsThatBecomeEmpty,
		}).Run()
	}

	return self.BeginInteractiveRebaseForCommitRange(commits, commitIndex, commitIndex, keepCommitsThatBecomeEmpty)
}

func (self *RebaseCommands) BeginInteractiveRebaseForCommitRange(
	commits []*models.Commit, start, end int, keepCommitsThatBecomeEmpty bool,
) error {
	if len(commits)-1 < end {
		return errors.New("index outside of range of commits")
	}

	// we can make this GPG thing possible it just means we need to do this in two parts:
	// one where we handle the possibility of a credential request, and the other
	// where we continue the rebase
	if self.config.NeedsGpgSubprocessForCommit() {
		return errors.New(self.Tr.DisabledForGPG)
	}

	changes := make([]daemon.ChangeTodoAction, 0, end-start)
	for commitIndex := end; commitIndex >= start; commitIndex-- {
		changes = append(changes, daemon.ChangeTodoAction{
			Hash:      commits[commitIndex].Hash(),
			NewAction: todo.Edit,
		})
	}
	self.os.LogCommand(logTodoChanges(changes), false)

View on GitHub (pinned to c477a2959b)

Solutions

  1. Validate `end < len(commits)` (and start <= end) at the call site with a freshly refreshed commits slice
  2. Trigger a commits refresh and recompute the selection before invoking
  3. In scripts, derive indexes from the same []*models.Commit you pass in

Example fix

// before
err := rebaseCmd.BeginInteractiveRebaseForCommitRange(commits, start, end, false)

// after
if end >= len(commits) || start > end {
    return fmt.Errorf("invalid commit range %d..%d of %d commits", start, end, len(commits))
}
err := rebaseCmd.BeginInteractiveRebaseForCommitRange(commits, start, end, false)
Defensive patterns

Strategy: validation

Validate before calling

if start < 0 || end < start || end >= len(commits) {
    return fmt.Errorf("range %d..%d invalid for %d commits", start, end, len(commits))
}
return rebaseCmd.BeginInteractiveRebaseForCommitRange(commits, start, end, keepEmpty)

Try / catch

On 'index outside of range of commits', refresh commits and recompute indexes exactly once; a second failure means the caller's model plumbing is wrong — fix that, don't retry.

Prevention

When it happens

Trigger: Calling the range rebase with an end index computed from an older model snapshot; controllers passing selection indexes after the log shrank (branch switched, commits squashed away); direct API use in tests.

Common situations: Racing a background refresh; selecting a deep commit then the history changing; programmatic callers reusing cached indexes.

Related errors


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