{"record":{"id":"df3130c30ceae8a8","repo":"jesseduffield/lazygit","slug":"could-not-find-deleted-file-or-new-file-for-file-r","errorCode":null,"errorMessage":"Could not find deleted file or new file for file rename","messagePattern":"Could not find deleted file or new file for file rename","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/commands/git_commands/working_tree.go","lineNumber":111,"sourceCode":"\t// all files, passing the --no-renames flag and then recursively call the function\n\t// again for the before file and after file.\n\n\tfilesWithoutRenames := self.fileLoader.GetStatusFiles(GetStatusFileOptions{NoRenames: true})\n\n\tvar beforeFile *models.File\n\tvar afterFile *models.File\n\tfor _, f := range filesWithoutRenames {\n\t\tif f.Path == file.PreviousPath {\n\t\t\tbeforeFile = f\n\t\t}\n\n\t\tif f.Path == file.Path {\n\t\t\tafterFile = f\n\t\t}\n\t}\n\n\tif beforeFile == nil || afterFile == nil {\n\t\treturn nil, nil, errors.New(\"Could not find deleted file or new file for file rename\")\n\t}\n\n\tif beforeFile.IsRename() || afterFile.IsRename() {\n\t\t// probably won't happen but we want to ensure we don't get an infinite loop\n\t\treturn nil, nil, errors.New(\"Nested rename found\")\n\t}\n\n\treturn beforeFile, afterFile, nil\n}\n\n// DiscardAllFileChanges directly\nfunc (self *WorkingTreeCommands) DiscardAllFileChanges(file *models.File) error {\n\tif file.IsRename() {\n\t\tbeforeFile, afterFile, err := self.BeforeAndAfterFileForRename(file)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/jesseduffield/lazygit/blob/c477a2959b229fbf3284be0d4d2904ab61ec3c94/pkg/commands/git_commands/working_tree.go#L93-L129","documentation":"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.","triggerScenarios":"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.","commonSituations":"Acting on a rename in the files panel right as a background refresh or another process (editor, formatter, second git invocation) changed the worktree.","solutions":["Refresh the files panel / rerun the action so the model matches the worktree","Ensure no concurrent process is mutating the index while lazygit acts","If persistent, run `git status --no-renames` manually and compare against what lazygit shows to spot path encoding oddities"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"freshFiles := fileLoader.GetStatusFiles(GetStatusFileOptions{NoRenames: true})\nhaveBefore, haveAfter := false, false\nfor _, f := range freshFiles {\n    haveBefore = haveBefore || f.Path == file.PreviousPath\n    haveAfter = haveAfter || f.Path == file.Path\n}\nif !haveBefore || !haveAfter {\n    return nil, nil, errors.New(\"rename halves not visible in current status; refresh\")\n}","typeGuard":null,"tryCatchPattern":"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.","preventionTips":["Avoid mutating the index from outside lazygit while using it","Trigger a files refresh after external commands (formatters, editors)","Don't hold *models.File pointers across user pauses"],"tags":["git","rename","model-staleness","working-tree"],"backgroundTag":null,"analyzedSha":"c477a2959b229fbf3284be0d4d2904ab61ec3c94","analyzedAt":"2026-08-15T08:34:32.451Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}