caddyserver/caddy · error

writing confirmation bytes to %s: %v

Error message

writing confirmation bytes to %s: %v

What it means

Returned by the `caddy run --pingback` child when writing the confirmation bytes to the established TCP connection fails. The dial succeeded but the write failed — the parent closed the connection first (it gave up, timed out, or was killed), or the connection was reset mid-write. The message includes the pingback address to identify the target.

Source

Thrown at cmd/commandfuncs.go:316

	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)
	}

	// warn if the environment does not provide enough information about the disk
	hasXDG := os.Getenv("XDG_DATA_HOME") != "" &&
		os.Getenv("XDG_CONFIG_HOME") != "" &&
		os.Getenv("XDG_CACHE_HOME") != ""

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Retry `caddy start`; if config provisioning is slow, address the slowness (large cert loads, remote module fetches)
  2. Check dmesg/systemd logs for OOM kills of the parent process
  3. Prefer `caddy run` under a proper service manager, which needs no pingback handshake
Defensive patterns

Strategy: retry

Try / catch

// child-side write failure to pingback: parent stopped listening
if err != nil && strings.Contains(err.Error(), "writing confirmation bytes") {
    // parent gave up; child can continue serving or exit per policy — do not hot-loop
}

Prevention

When it happens

Trigger: Parent `caddy start` timed out waiting and closed its listener/accepted connection before the child wrote; parent killed in the window between accept and write; loopback connection reset by the OS or a security layer.

Common situations: Slow-starting configs (expensive provisioning) where the parent's wait window closes first; OOM or signal-based termination of the parent at exactly the wrong moment; essentially an internal handshake race.

Related errors


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