{"record":{"id":"262055f1d8ffb079","repo":"jesseduffield/lazygit","slug":"update-failed-errmessage","errorCode":null,"errorMessage":"Update failed: {{.errMessage}}","messagePattern":"Update failed: (.+?)\\}","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/gui/controllers/helpers/update_helper.go","lineNumber":76,"sourceCode":"func (self *UpdateHelper) startUpdating(newVersion string) {\n\t_ = self.c.WithWaitingStatus(self.c.Tr.UpdateInProgressWaitingStatus, func(gocui.Task) error {\n\t\tself.c.State().SetUpdating(true)\n\t\terr := self.updater.Update(newVersion)\n\t\treturn self.onUpdateFinish(err)\n\t})\n}\n\nfunc (self *UpdateHelper) onUpdateFinish(err error) error {\n\tself.c.State().SetUpdating(false)\n\tself.c.OnUIThread(func() error {\n\t\tself.c.SetViewContent(self.c.Views().AppStatus, \"\")\n\t\tif err != nil {\n\t\t\terrMessage := utils.ResolvePlaceholderString(\n\t\t\t\tself.c.Tr.UpdateFailedErr, map[string]string{\n\t\t\t\t\t\"errMessage\": err.Error(),\n\t\t\t\t},\n\t\t\t)\n\t\t\treturn errors.New(errMessage)\n\t\t}\n\t\tself.c.Alert(self.c.Tr.UpdateCompletedTitle, self.c.Tr.UpdateCompleted)\n\t\treturn nil\n\t})\n\n\treturn nil\n}\n\nfunc (self *UpdateHelper) showUpdatePrompt(newVersion string) error {\n\tmessage := utils.ResolvePlaceholderString(\n\t\tself.c.Tr.UpdateAvailable, map[string]string{\n\t\t\t\"newVersion\": newVersion,\n\t\t},\n\t)\n\n\tself.c.Confirm(types.ConfirmOpts{\n\t\tTitle:  self.c.Tr.UpdateAvailableTitle,\n\t\tPrompt: message,","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/jesseduffield/lazygit/blob/c477a2959b229fbf3284be0d4d2904ab61ec3c94/pkg/gui/controllers/helpers/update_helper.go#L58-L94","documentation":"Produced by UpdateHelper.onUpdateFinish after the self-update subprocess fails: the raw updater error is wrapped into the UpdateFailedErr template ('Update failed: {{.errMessage}}') and shown on the UI thread after clearing the status view and flipping the updating flag off. It is a terminal report of a failed binary replacement — no retry is scheduled.","triggerScenarios":"Accepting the update prompt and the download/verify/replace step failing: no write permission on the running binary, download interrupted, checksum verification failure, or an unsupported platform/release-asset layout.","commonSituations":"lazygit installed to a root-owned or package-manager-owned path (/usr/bin, /opt/homebrew owned by brew) so replacing the binary fails; corporate proxies truncating downloads; running from a read-only mount (NFS, snap confinement); version feed advertising an asset missing for the OS/arch.","solutions":["Check the embedded errMessage — it names the concrete cause (permissions, 404 asset, checksum).","If the binary is package-manager owned, update via that package manager and disable in-app updates.","For permission issues, update manually: download the release tarball and replace the binary in a PATH dir you own (~/.local/bin).","Retry on a stable network if the failure was a truncated download."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// before updating, confirm the binary is replaceable:\nif info, err := os.Stat(os.Executable()); err != nil || info.Mode().Perm()&0o200 == 0 {\n    // update manually instead of in-app self-update\n}","typeGuard":null,"tryCatchPattern":"err := updater.Update(newVersion)\nif err != nil {\n    // err.Error() already carries the root cause inside UpdateFailedErr;\n    // branch on it: permissions -> manual update, network -> retry once\n}","preventionTips":["Install lazygit in a user-owned PATH dir (~/.local/bin) so self-update can replace the binary","Use the package manager for package-manager installs","Read the embedded errMessage — it distinguishes 404 asset vs permission vs checksum"],"tags":["update","self-update","permissions","download","packaging"],"backgroundTag":null,"analyzedSha":"c477a2959b229fbf3284be0d4d2904ab61ec3c94","analyzedAt":"2026-08-15T08:34:32.451Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}