{"record":{"id":"4da5c536aff67304","repo":"gravitational/teleport","slug":"executable-has-unstable-path","errorCode":null,"errorMessage":"executable has unstable path","messagePattern":"executable has unstable path","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"lib/autoupdate/agent/integrations.go","lineNumber":40,"sourceCode":"\t\"context\"\n\t\"errors\"\n\t\"io/fs\"\n\t\"log/slog\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/gravitational/trace\"\n\n\t\"github.com/gravitational/teleport/api/types\"\n)\n\nvar (\n\t// ErrConfigNotFound is returned by HellorUpdaterInfo when the updater config file cannot be found.\n\tErrConfigNotFound = errors.New(\"updater config file not found\")\n\n\t// ErrUnstableExecutable is returned by StableExecutable when no stable path can be found.\n\tErrUnstableExecutable = errors.New(\"executable has unstable path\")\n)\n\nconst updateConfigFileEnvVar = \"TELEPORT_UPDATE_CONFIG_FILE\"\n\n// IsManagedByUpdater returns true if the local Teleport binary is managed by teleport-update.\n// Note that true may be returned even if auto-updates is disabled or the version is pinned.\n// The binary is considered managed if it lives under /opt/teleport, but not within the package\n// path at /opt/teleport/system.\nfunc IsManagedByUpdater() (bool, error) {\n\tsystemd, err := hasSystemD()\n\tif err != nil {\n\t\treturn false, trace.Wrap(err)\n\t}\n\tif !systemd {\n\t\treturn false, nil\n\t}\n\tteleportPath, err := os.Executable()\n\tif err != nil {","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/gravitational/teleport/blob/1283425b60ec5f60d509ba4c791183d452923ff7/lib/autoupdate/agent/integrations.go#L22-L58","documentation":"ErrUnstableExecutable is returned by StableExecutable/stablePathForBinary when a stable, version-independent path to the Teleport binary cannot be resolved. The unstable path (from os.Executable()) is still returned alongside the error so callers can proceed, but the path points at a specific versioned binary that may disappear after an update.","triggerScenarios":"Calling StableExecutable when: (1) the binary lives in a package install (<packageSystemDir>/bin/<name>) but /usr/local/bin/<name> does not exist or does not stat (integrations.go:103); or (2) the binary is a Managed Updates install and update.yaml exists but cfg.Spec.Path is empty or the target link path <cfg.Spec.Path>/<name> fails os.Stat (integrations.go:122).","commonSituations":"Package (deb/rpm) installs where the /usr/local/bin symlink was deleted or never created; Managed Updates installs whose update.yaml points to a path that was moved, deleted, or never linked; partially completed upgrades leaving the versions dir without a working stable link.","solutions":["For package installs, recreate the stable symlink: ln -s /opt/teleport/system/bin/teleport /usr/local/bin/teleport (matching name).","For Managed Updates, inspect update.yaml (cfg.Spec.Path) and ensure the path exists and contains the binary; re-run teleport-update to repair links.","Re-run the installer/upgrade to restore the stable link path, or hard-restart the service so it resolves the new binary.","Handle the error in callers: use the returned unstable path but treat it as ephemeral — do not persist it across updates."],"exampleFix":"// before\np, err := autoupdate.StableExecutable()\nif err != nil { return err }\n// after\np, err := autoupdate.StableExecutable()\nif errors.Is(err, autoupdate.ErrUnstableExecutable) {\n    // p is still valid but version-specific; use it, don't persist it\n} else if err != nil {\n    return err\n}","handlingStrategy":"type-guard","validationCode":"// Pre-check the stable link before calling:\nif _, err := os.Stat(\"/usr/local/bin/teleport\"); err != nil {\n    // stable link missing: repair it or expect ErrUnstableExecutable\n}","typeGuard":"func isUnstableExecutable(err error) bool { return errors.Is(err, autoupdate.ErrUnstableExecutable) }","tryCatchPattern":"p, err := autoupdate.StableExecutable()\nswitch {\ncase errors.Is(err, autoupdate.ErrUnstableExecutable):\n    // p is valid but version-specific; use ephemeral, do not persist\ncase err != nil:\n    return trace.Wrap(err)\n}","preventionTips":["Keep /usr/local/bin/<name> symlinks intact for package installs.","Verify cfg.Spec.Path in update.yaml exists after every upgrade.","Never treat the path returned with ErrUnstableExecutable as durable across updates."],"tags":["autoupdate","filesystem","go","sentinel-error"],"backgroundTag":"unstable-executable-path","analyzedSha":"1283425b60ec5f60d509ba4c791183d452923ff7","analyzedAt":"2026-09-02T04:06:41.601Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}