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
- Retry `caddy start`; if config provisioning is slow, address the slowness (large cert loads, remote module fetches)
- Check dmesg/systemd logs for OOM kills of the parent process
- 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
- Give `caddy start` a wait window longer than the slowest expected provisioning
- Address slow provisioning (huge cert sets, remote fetches) so the handshake completes promptly
- Use `caddy run` under systemd for deterministic startup without pingback races
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
- reading confirmation bytes from stdin: %v
- dialing confirmation address: %v
- opening listener for success confirmation: %v
- listen on 127.0.0.1:0: %v; listen on [::1]:0: %v
- loading initial config: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/e075a70f9e2ecbdb.
Report an issue: GitHub.