jesseduffield/lazygit · error

Could not find deleted file or new file for file rename

Error message

Could not find deleted file or new file for file rename

What it means

After refetching the status with --no-renames, BeforeAndAfterFileForRename must find entries matching file.PreviousPath (the deleted side) and file.Path (the added side). If either is missing from the no-renames listing, the rename cannot be split and the error fires. It indicates the file model and the actual working-tree/HEAD status disagree.

Source

Thrown at pkg/commands/git_commands/working_tree.go:111

	// all files, passing the --no-renames flag and then recursively call the function
	// again for the before file and after file.

	filesWithoutRenames := self.fileLoader.GetStatusFiles(GetStatusFileOptions{NoRenames: true})

	var beforeFile *models.File
	var afterFile *models.File
	for _, f := range filesWithoutRenames {
		if f.Path == file.PreviousPath {
			beforeFile = f
		}

		if f.Path == file.Path {
			afterFile = f
		}
	}

	if beforeFile == nil || afterFile == nil {
		return nil, nil, errors.New("Could not find deleted file or new file for file rename")
	}

	if beforeFile.IsRename() || afterFile.IsRename() {
		// probably won't happen but we want to ensure we don't get an infinite loop
		return nil, nil, errors.New("Nested rename found")
	}

	return beforeFile, afterFile, nil
}

// DiscardAllFileChanges directly
func (self *WorkingTreeCommands) DiscardAllFileChanges(file *models.File) error {
	if file.IsRename() {
		beforeFile, afterFile, err := self.BeforeAndAfterFileForRename(file)
		if err != nil {
			return err
		}

View on GitHub (pinned to c477a2959b)

Solutions

  1. Refresh the files panel / rerun the action so the model matches the worktree
  2. Ensure no concurrent process is mutating the index while lazygit acts
  3. If persistent, run `git status --no-renames` manually and compare against what lazygit shows to spot path encoding oddities
Defensive patterns

Strategy: retry

Validate before calling

freshFiles := fileLoader.GetStatusFiles(GetStatusFileOptions{NoRenames: true})
haveBefore, haveAfter := false, false
for _, f := range freshFiles {
    haveBefore = haveBefore || f.Path == file.PreviousPath
    haveAfter = haveAfter || f.Path == file.Path
}
if !haveBefore || !haveAfter {
    return nil, nil, errors.New("rename halves not visible in current status; refresh")
}

Try / catch

On this error, re-fetch file status and retry the discard/split once — the usual cause is a stale model catching up. A second failure means genuine worktree divergence; stop and surface the state to the user.

Prevention

When it happens

Trigger: Stale file model: the rename was already staged/discarded/committed between refresh and action; paths needing quoting where the listing round-trips differently; submodules or symlinks that never appear as separate delete+add pairs under --no-renames.

Common situations: Acting on a rename in the files panel right as a background refresh or another process (editor, formatter, second git invocation) changed the worktree.

Related errors


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