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
- Validate `end < len(commits)` (and start <= end) at the call site with a freshly refreshed commits slice
- Trigger a commits refresh and recompute the selection before invoking
- 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
- Derive start/end from the commits slice passed in, never from a cached selection
- Refresh after rebase/completion callbacks before allowing new selections
- Unit-test index math against 0-, 1-, and N-length commit slices
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
- index outside of range of commits
- Todo %s not found in git-rebase-todo
- Feature not available for users using GPG. If you are using
- You are midway through another rebase operation. Please abor
- Feature not available for users using GPG. If you are using
AI-assisted analysis of jesseduffield/lazygit@c477a2959b (2026-08-15).
Data as JSON: /api/errors/f682bbab88cbe0ff.
Report an issue: GitHub.