tailscale/tailscale · error
cannot find %q in neither %q nor $PATH: %w
Error message
cannot find %q in neither %q nor $PATH: %w
What it means
The binaryPaths helper (used by unpackLinuxTarball and friends) resolves the current executable via os.Executable, derives the companion name (tailscale <-> tailscaled), looks for it next to the current binary, and falls back to exec.LookPath. This error means neither the same directory nor $PATH yielded the companion binary, so the updater cannot know where to install both halves of the update.
Source
Thrown at clientupdate/clientupdate.go:1280
var binaryPaths = func() (tailscale, tailscaled string, err error) {
// This can be either tailscale or tailscaled.
this, err := os.Executable()
if err != nil {
return "", "", err
}
otherName := "tailscaled"
if filepath.Base(this) == "tailscaled" {
otherName = "tailscale"
}
// Try to find the other binary in the same directory.
other := filepath.Join(filepath.Dir(this), otherName)
_, err = os.Stat(other)
if os.IsNotExist(err) {
// If it's not in the same directory, try to find it in $PATH.
other, err = exec.LookPath(otherName)
}
if err != nil {
return "", "", fmt.Errorf("cannot find %q in neither %q nor $PATH: %w", otherName, filepath.Dir(this), err)
}
if otherName == "tailscaled" {
return this, other, nil
} else {
return other, this, nil
}
}
func haveExecutable(name string) bool {
path, err := exec.LookPath(name)
return err == nil && path != ""
}
func requestedTailscaleVersion(ver, track string) (string, error) {
if ver != "" {
return ver, nil
}
return LatestTailscaleVersion(track)View on GitHub (pinned to cfe32b8be6)
Solutions
- Install both binaries into the same directory: place tailscale and tailscaled side by side (as the official tarball layout does)
- Or ensure the companion's directory is on PATH: sudo env "PATH=$PATH" tailscale update, or extend secure_path in /etc/sudoers
- Symlink the missing companion into the current binary's directory: ln -s /usr/sbin/tailscaled "$(dirname "$(command -v tailscale)")"/tailscaled
- On systems where tailscaled genuinely runs elsewhere (container setups), update through that system's native package manager instead
Example fix
# before: tailscale in ~/bin, tailscaled in /usr/sbin not on PATH $ tailscale update cannot find "tailscaled" in neither "/home/user/bin" nor $PATH: exec: "tailscaled": executable file not found in $PATH # after: keep both binaries together $ sudo cp tailscale tailscaled /usr/local/bin/ && hash -r $ sudo /usr/local/bin/tailscale update
Defensive patterns
Strategy: validation
Validate before calling
// Ensure both binaries resolve before starting an update
func bothBinariesResolvable() error {
self, err := os.Executable()
if err != nil { return err }
other := "tailscaled"
if filepath.Base(self) == "tailscaled" { other = "tailscale" }
if _, err := os.Stat(filepath.Join(filepath.Dir(self), other)); err == nil { return nil }
if _, err := exec.LookPath(other); err != nil {
return fmt.Errorf("companion %s not next to %s nor on PATH", other, self)
}
return nil
} Type guard
func isCompanionBinaryMissing(err error) bool {
return err != nil && strings.Contains(err.Error(), "in neither") && strings.Contains(err.Error(), "nor $PATH")
} Try / catch
if err := up.Update(ctx); err != nil {
if isCompanionBinaryMissing(err) {
// install/symlink the companion binary, then retry the update once
log.Printf("place tailscale and tailscaled in the same directory or extend PATH")
}
return err
} Prevention
- Install tailscale and tailscaled side by side from the official tarball layout
- When invoking via sudo, remember secure_path may exclude /usr/sbin — use sudo env PATH=$PATH:... or full paths
- In containers, set PATH to include the directory holding both binaries or avoid the in-place updater
When it happens
Trigger: Only the tailscale CLI was copied somewhere without tailscaled (manual tarball extraction), or tailscaled lives in a directory absent from the invoking user's PATH (e.g. /usr/sbin stripped by sudo's secure_path or a minimal container PATH).
Common situations: Running a standalone tailscale binary from ~/bin or /tmp while tailscaled runs from /usr/sbin; containers with a minimal PATH where systemd isn't running tailscaled locally; invoking via sudo with a restricted secure_path.
Related errors
- expected %s to exist, got stat error: %w
- duration out of range
- API response too large
- unable to create /userdata/init.d
- /etc/pve is not a directory: run this on a Proxmox VE host
AI-assisted analysis of tailscale/tailscale@cfe32b8be6 (2026-08-15).
Data as JSON: /api/errors/4442829154dec561.
Report an issue: GitHub.