{"record":{"id":"5cf2b96b7e267805","repo":"matryer/xbar","slug":"get-executable","errorCode":null,"errorMessage":"get executable","messagePattern":"get executable","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/update/update.go","lineNumber":86,"sourceCode":"\t\t}\n\t}\n\tif selectedAsset == nil {\n\t\treturn nil, errors.New(\"no asset selected, use SelectAssetFunc to select an asset\")\n\t}\n\terr = u.downloadAndReplaceApp(*selectedAsset)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"download update\")\n\t}\n\treturn latest, nil\n}\n\n// Restart spawns the current executable again, and terminates\n// the running one.\nfunc (u *Updater) Restart() error {\n\ttime.Sleep(1 * time.Second)\n\tthisExecuable, err := os.Executable()\n\tif err != nil {\n\t\treturn errors.Wrap(err, \"get executable\")\n\t}\n\tlog.Println(\"restarting\", thisExecuable)\n\tcmd := exec.Command(thisExecuable)\n\tcmd.SysProcAttr = &syscall.SysProcAttr{\n\t\tSetpgid: false,\n\t}\n\tcmd.Dir = filepath.Dir(thisExecuable)\n\tcmd.Env = os.Environ()\n\tcmd.Env = append(cmd.Env, \"XBAR_UPDATE_RESTART_COUNTER=1\")\n\tcmd.Args = os.Args\n\tcmd.Stdout = os.Stdout\n\tcmd.Stderr = os.Stderr\n\terr = cmd.Start()\n\tif err != nil {\n\t\tif exitErr, ok := err.(*exec.ExitError); ok {\n\t\t\treturn errors.Wrapf(err, \"starting new app failed: exit code %d\", exitErr.ExitCode())\n\t\t}\n\t\treturn errors.Wrap(err, \"starting new app failed\")","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/matryer/xbar/blob/d624239058997c80118eaebe2e7f8331b3c765e0/pkg/update/update.go#L68-L104","documentation":"This error is wrapped by Updater.Restart (pkg/update/update.go:86) when os.Executable() fails to resolve the path of the currently running executable. Restart needs this path to spawn a fresh instance after an update; without it the restart cannot proceed. os.Executable fails rarely, typically when the binary has been deleted or renamed while running.","triggerScenarios":"Restart() calls os.Executable() (pkg/update/update.go:86) and the OS returns an error — usually because the executable file was deleted or replaced/unlinked from disk after the process started, or on some platforms when /proc-style lookup fails (deleted inode, restricted procfs in minimal containers).","commonSituations":"Auto-update deleted the old binary and then a restart is attempted in the same process; running inside a minimal container (distroless/scratch) where /proc/self/exe lookup is unavailable or the path no longer exists; binary run via a symlink whose target was removed; deleted-but-running process (deleted suffix path).","solutions":["Keep the original executable on disk until after Restart completes (replace, don't delete, before restarting)","Restart the process externally (systemd, supervisor, docker restart) instead of self-restarting when running in minimal containers","If running under a deleted path, exec the new binary directly rather than relying on os.Executable()","On Linux, verify /proc/self/exe resolves before calling Restart","Log the underlying errno from the wrapped error to confirm the deleted-binary scenario"],"exampleFix":"// before\nif err := updater.Restart(); err != nil {\n\tlog.Fatal(err)\n}\n// after\nif err := updater.Restart(); err != nil {\n\tlog.Printf(\"self-restart failed (%v); requesting supervisor restart\", err)\n\tos.Exit(0) // let systemd/supervisor restart the updated binary\n}","handlingStrategy":"fallback","validationCode":"exe, err := os.Executable()\nif err != nil {\n\tif _, statErr := os.Stat(\"/proc/self/exe\"); statErr != nil {\n\t\treturn fmt.Errorf(\"cannot resolve executable path; self-restart unavailable: %w\", err)\n\t}\n}\nif strings.Contains(exe, \" (deleted)\") {\n\treturn fmt.Errorf(\"binary deleted on disk; external restart required\")\n}","typeGuard":null,"tryCatchPattern":"if err := updater.Restart(); err != nil {\n\tif strings.Contains(fmt.Sprintf(\"%+v\", err), \"get executable\") {\n\t\tlog.Printf(\"self-restart impossible (%v); exiting for supervisor restart\", err)\n\t\tos.Exit(0)\n\t}\n\treturn err\n}","preventionTips":["Replace the binary in place (rename-into-place) instead of deleting before restart","Use a process supervisor (systemd, k8s, docker --restart) as the restart mechanism in minimal containers","Check for a deleted binary before attempting self-restart","Verify /proc is mounted when running in containers that self-update"],"tags":["go","process","self-update","os-executable"],"backgroundTag":"executable-path-resolution-failed","analyzedSha":"d624239058997c80118eaebe2e7f8331b3c765e0","analyzedAt":"2026-09-02T22:38:22.007Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}