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

  1. Retry `caddy start` ensuring the parent process stays alive through startup (no aggressive timeouts)
  2. Verify loopback connectivity in the environment: curl http://127.0.0.1:1/ should get a connection refused, not a permission error
  3. Relax sandbox/seccomp rules that block loopback connect()
  4. 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

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


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/316c7ece5866f55b. Report an issue: GitHub.