caddyserver/caddy · error
resolving current executable symlink: %v
Error message
resolving current executable symlink: %v
What it means
The running Caddy executable is a symlink (detected via the stat mode bits) and filepath.EvalSymlinks failed while resolving it to the real target. The upgrade must replace the actual file, not the link, so an unresolvable symlink aborts the operation.
Source
Thrown at cmd/packagesfuncs.go:140
}
func upgradeBuild(pluginPkgs map[string]pluginPackage, fl Flags) (int, error) {
l := caddy.Log()
thisExecPath, err := os.Executable()
if err != nil {
return caddy.ExitCodeFailedStartup, fmt.Errorf("determining current executable path: %v", err)
}
thisExecStat, err := os.Stat(thisExecPath)
if err != nil {
return caddy.ExitCodeFailedStartup, fmt.Errorf("retrieving current executable permission bits: %v", err)
}
if thisExecStat.Mode()&os.ModeSymlink == os.ModeSymlink {
symSource := thisExecPath
// we are a symlink; resolve it
thisExecPath, err = filepath.EvalSymlinks(thisExecPath)
if err != nil {
return caddy.ExitCodeFailedStartup, fmt.Errorf("resolving current executable symlink: %v", err)
}
l.Info("this executable is a symlink", zap.String("source", symSource), zap.String("target", thisExecPath))
}
l.Info("this executable will be replaced", zap.String("path", thisExecPath))
// build the request URL to download this custom build
qs := url.Values{
"os": {runtime.GOOS},
"arch": {runtime.GOARCH},
}
for _, pkgInfo := range pluginPkgs {
qs.Add("p", pkgInfo.String())
}
// initiate the build
resp, err := downloadBuild(qs)
if err != nil {
return caddy.ExitCodeFailedStartup, fmt.Errorf("download failed: %v", err)View on GitHub (pinned to 50e54ee279)
Solutions
- Inspect the link: `readlink -f $(which caddy)` — if it errors or points nowhere, restore the target binary
- Re-download a real binary to the target path (curl the caddyserver.com download API) or rebuild with xcaddy, keeping the symlink intact
- Alternatively replace the symlink with the actual binary to avoid future resolution issues
Example fix
# before caddy upgrade # /usr/local/bin/caddy -> missing target # after curl -sSL 'https://caddyserver.com/api/download?os=linux&arch=amd64' -o /opt/caddy/caddy caddy upgrade
Defensive patterns
Strategy: validation
Validate before calling
P=$(command -v caddy) if [ -L "$P" ]; then T=$(readlink -f "$P") && [ -e "$T" ] || echo "broken symlink: $P -> target missing; restore target first"; fi
Prevention
- Point symlinks at durable target paths
- After any failed upgrade, check the symlink target still exists before retrying
When it happens
Trigger: A broken symlink (target deleted — often the aftermath of a previous upgrade that moved the real binary to `.tmp`), a symlink loop, or a symlink chain crossing into an unreachable mount.
Common situations: `/usr/local/bin/caddy -> /opt/caddy/caddy` where /opt/caddy/caddy was removed; nix/homebrew-style symlinks whose target was garbage-collected; containers with dangling symlinked binaries.
Related errors
- retrieving current executable permission bits: %v
- unable to enumerate installed plugins: %v
- download failed: %v
- backing up current binary: %v
- checking if default Caddyfile exists: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/7b7fa581699d6f6a.
Report an issue: GitHub.