caddyserver/caddy · error
dialing confirmation address: %v
Error message
dialing confirmation address: %v
What it means
Returned by the `caddy run --pingback` child when net.Dial to the parent's pingback address fails. The parent listens on 127.0.0.1:0 or [::1]:0 and passes the concrete address via --pingback; dial failure means the parent's listener is gone or loopback dialing is blocked. This prevents the child from confirming successful startup.
Source
Thrown at cmd/commandfuncs.go:311
// log normally, now that the config is running.
// also clear our ref to the buffer so it can get GC'd
logger = caddy.Log()
defaultLogger = nil //nolint:ineffassign,wastedassign
logBuffer = nil //nolint:wastedassign,ineffassign
logger.Info("serving initial configuration")
// if we are to report to another process the successful start
// of the server, do so now by echoing back contents of stdin
if pingbackFlag != "" {
confirmationBytes, err := io.ReadAll(os.Stdin)
if err != nil {
return caddy.ExitCodeFailedStartup,
fmt.Errorf("reading confirmation bytes from stdin: %v", err)
}
conn, err := net.Dial("tcp", pingbackFlag)
if err != nil {
return caddy.ExitCodeFailedStartup,
fmt.Errorf("dialing confirmation address: %v", err)
}
_, err = conn.Write(confirmationBytes)
if err != nil {
return caddy.ExitCodeFailedStartup,
fmt.Errorf("writing confirmation bytes to %s: %v", pingbackFlag, err)
}
// close (non-defer because we `select {}` below)
// and release references so they can be GC'd
conn.Close()
confirmationBytes = nil //nolint:ineffassign,wastedassign
conn = nil //nolint:wastedassign,ineffassign
}
// if enabled, reload config file automatically on changes
// (this better only be used in dev!)
if watchFlag {
go watchConfigFile(configFile, adapterUsed)
}View on GitHub (pinned to 50e54ee279)
Solutions
- Retry `caddy start` ensuring the parent process stays alive through startup (no aggressive timeouts)
- Verify loopback connectivity in the environment: curl http://127.0.0.1:1/ should get a connection refused, not a permission error
- Relax sandbox/seccomp rules that block loopback connect()
- Use `caddy run` under systemd/supervisor instead of the start/pingback handshake
Defensive patterns
Strategy: retry
Validate before calling
// pre-flight in the parent: loopback dial works
if conn, err := net.DialTimeout("tcp", "127.0.0.1:1", time.Second); err == nil {
conn.Close()
} else if strings.Contains(err.Error(), "permission denied") {
return errors.New("loopback dial blocked by policy; fix sandbox rules")
} Try / catch
// child-side: dial failure with parent gone => exit; parent will observe child exit instead
if err != nil && strings.Contains(err.Error(), "dialing confirmation address") {
// parent listener vanished; safe to exit non-zero, do not loop
} Prevention
- Keep the `caddy start` parent alive through the full startup window
- Allow loopback connect() in seccomp/SELinux profiles for Caddy
- Prefer `caddy run` under a supervisor to skip the handshake entirely
When it happens
Trigger: Parent `caddy start` exited (crash, kill) before the child dialed back; firewall/SELinux blocking loopback connections; container network policy dropping loopback TCP; the address string corrupted by a wrapper.
Common situations: Race where the parent is killed immediately after spawn (supervisors, scripts with short timeouts); hardened sandboxes (gVisor, custom seccomp) denying loopback connect.
Related errors
- writing confirmation bytes to %s: %v
- opening listener for success confirmation: %v
- listen on 127.0.0.1:0: %v; listen on [::1]:0: %v
- reading confirmation bytes from stdin: %v
- loading initial config: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/316c7ece5866f55b.
Report an issue: GitHub.