{"record":{"id":"25e258f284941e23","repo":"caddyserver/caddy","slug":"wrong-confirmation-x","errorCode":null,"errorMessage":"wrong confirmation: %x","messagePattern":"wrong confirmation: %x","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/main.go","lineNumber":90,"sourceCode":"\tif err := defaultFactory.Build().Execute(); err != nil {\n\t\tvar exitError *exitError\n\t\tif errors.As(err, &exitError) {\n\t\t\tos.Exit(exitError.ExitCode)\n\t\t}\n\t\tos.Exit(1)\n\t}\n}\n\n// handlePingbackConn reads from conn and ensures it matches\n// the bytes in expect, or returns an error if it doesn't.\nfunc handlePingbackConn(conn net.Conn, expect []byte) error {\n\tdefer conn.Close()\n\tconfirmationBytes, err := io.ReadAll(io.LimitReader(conn, 32))\n\tif err != nil {\n\t\treturn err\n\t}\n\tif !bytes.Equal(confirmationBytes, expect) {\n\t\treturn fmt.Errorf(\"wrong confirmation: %x\", confirmationBytes)\n\t}\n\treturn nil\n}\n\n// LoadConfig loads the config from configFile and adapts it\n// using adapterName. If adapterName is specified, configFile\n// must be also. If no configFile is specified, it tries\n// loading a default config file. The lack of a config file is\n// not treated as an error, but false will be returned if\n// there is no config available. It prints any warnings to stderr,\n// and returns the resulting JSON config bytes along with\n// the name of the loaded config file (if any).\n// The return values are:\n//   - config bytes (nil if no config)\n//   - config file used (\"\" if none)\n//   - adapter used (\"\" if none)\n//   - error, if any\nfunc LoadConfig(configFile, adapterName string) ([]byte, string, string, error) {","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/cmd/main.go#L72-L108","documentation":"Internal fork/exec handshake: after spawning a child (e.g. 'caddy run' unsupervised start), the parent reads up to 32 confirmation bytes from a pipe and compares them to the expected token. A mismatch (including zero bytes if the child died) produces 'wrong confirmation' with the actual bytes hex-encoded.","triggerScenarios":"Child process crashes before writing its pingback token, writes garbage, or the pipe is closed early. Users see this as a startup failure right after 'caddy start'/'caddy run' forks.","commonSituations":"The child failing during early init (bad config, bind failure) so it never confirms; exotic environments (restricted containers) where the inherited pipe behaves unusually.","solutions":["Run 'caddy run' in the foreground to see the child's real startup error","Validate the config first: caddy validate --config <file>","Check logs (journalctl -u caddy or the configured log) for the child's panic/error"],"exampleFix":"# before\ncaddy start   # wrong confirmation: (empty)\n\n# after (foreground exposes the true error)\ncaddy run --config /etc/caddy/Caddyfile","handlingStrategy":"fallback","validationCode":"# Verify the config before backgrounded start so the child confirms cleanly:\ncaddy validate --config /etc/caddy/Caddyfile && caddy start --config /etc/caddy/Caddyfile","typeGuard":null,"tryCatchPattern":"if err := caddyStart(); err != nil { if strings.Contains(err.Error(), \"wrong confirmation\") { /* fall back to foreground 'caddy run' to expose the child's real error */ } }","preventionTips":["Prefer 'caddy run' in the foreground while iterating on configs","Validate configs before 'caddy start' — the pingback masks the child's init failure"],"tags":["cli","process-lifecycle","startup","internal"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}