caddyserver/caddy · error

opening listener for success confirmation: %v

Error message

opening listener for success confirmation: %v

What it means

Returned by `caddy start` when it cannot open the loopback TCP listener used to receive the child process's success pingback. Before spawning the detached child, the parent binds 127.0.0.1:0 (or [::1]:0 as fallback); failure means the OS refused a loopback listen — socket exhaustion, loopback disabled, or socket limits (ulimit).

Source

Thrown at cmd/commandfuncs.go:64

	configFlag := fl.String("config")
	configAdapterFlag := fl.String("adapter")
	pidfileFlag := fl.String("pidfile")
	watchFlag := fl.Bool("watch")

	var err error
	var envfileFlag []string
	envfileFlag, err = fl.GetStringSlice("envfile")
	if err != nil {
		return caddy.ExitCodeFailedStartup,
			fmt.Errorf("reading envfile flag: %v", err)
	}

	// open a listener to which the child process will connect when
	// it is ready to confirm that it has successfully started
	ln, err := listenTCPForPingback(net.Listen)
	if err != nil {
		return caddy.ExitCodeFailedStartup,
			fmt.Errorf("opening listener for success confirmation: %v", err)
	}
	defer ln.Close()

	// craft the command with a pingback address and with a
	// pipe for its stdin, so we can tell it our confirmation
	// code that we expect so that some random port scan at
	// the most unfortunate time won't fool us into thinking
	// the child succeeded (i.e. the alternative is to just
	// wait for any connection on our listener, but better to
	// ensure it's the process we're expecting - we can be
	// sure by giving it some random bytes and having it echo
	// them back to us)
	cmd := exec.Command(os.Args[0], "run", "--pingback", ln.Addr().String()) //nolint:gosec // no command injection that I can determine...
	// we should be able to run caddy in relative paths
	if errors.Is(cmd.Err, exec.ErrDot) {
		cmd.Err = nil
	}
	if configFlag != "" {

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Raise the file-descriptor limit: ulimit -n 4096 (or higher), then retry caddy start
  2. Verify loopback works: curl http://127.0.0.1:1/ or ss -ltn should not error
  3. In containers, ensure networking is not disabled (avoid --network none for caddy start)
  4. As a workaround use `caddy run` (foreground), which needs no pingback listener

Example fix

# before
caddy start  # opening listener for success confirmation: ... address already in use / too many open files
# after
ulimit -n 4096 && caddy start
Defensive patterns

Strategy: fallback

Validate before calling

// pre-flight: can we bind loopback at all?
ln, err := net.Listen("tcp4", "127.0.0.1:0")
if err != nil {
    return fmt.Errorf("loopback bind failed (%v) — raise ulimit -n or fix networking; use `caddy run` instead", err)
}
ln.Close()

Prevention

When it happens

Trigger: Running `caddy start` with file-descriptor limits exhausted (thousands of open sockets); a container with networking disabled or a broken loopback interface; SELinux/AppArmor denying socket() to the process; extremely rare kernel-level resource shortage.

Common situations: Heavily loaded hosts or CI runners out of FDs; minimal containers (network=none) where loopback TCP bind fails; security policies restricting listen sockets.

Related errors


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