{"record":{"id":"43faac176539ce54","repo":"caddyserver/caddy","slug":"reading-confirmation-bytes-from-stdin-v","errorCode":null,"errorMessage":"reading confirmation bytes from stdin: %v","messagePattern":"reading confirmation bytes from stdin: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/commandfuncs.go","lineNumber":306,"sourceCode":"\t// release the reference to the config so it can be GC'd\n\tconfig = nil //nolint:ineffassign,wastedassign\n\n\t// at this stage the config will have replaced the\n\t// default logger to the configured one, so we can\n\t// log normally, now that the config is running.\n\t// also clear our ref to the buffer so it can get GC'd\n\tlogger = caddy.Log()\n\tdefaultLogger = nil //nolint:ineffassign,wastedassign\n\tlogBuffer = nil     //nolint:wastedassign,ineffassign\n\tlogger.Info(\"serving initial configuration\")\n\n\t// if we are to report to another process the successful start\n\t// of the server, do so now by echoing back contents of stdin\n\tif pingbackFlag != \"\" {\n\t\tconfirmationBytes, err := io.ReadAll(os.Stdin)\n\t\tif err != nil {\n\t\t\treturn caddy.ExitCodeFailedStartup,\n\t\t\t\tfmt.Errorf(\"reading confirmation bytes from stdin: %v\", err)\n\t\t}\n\t\tconn, err := net.Dial(\"tcp\", pingbackFlag)\n\t\tif err != nil {\n\t\t\treturn caddy.ExitCodeFailedStartup,\n\t\t\t\tfmt.Errorf(\"dialing confirmation address: %v\", err)\n\t\t}\n\t\t_, err = conn.Write(confirmationBytes)\n\t\tif err != nil {\n\t\t\treturn caddy.ExitCodeFailedStartup,\n\t\t\t\tfmt.Errorf(\"writing confirmation bytes to %s: %v\", pingbackFlag, err)\n\t\t}\n\t\t// close (non-defer because we `select {}` below)\n\t\t// and release references so they can be GC'd\n\t\tconn.Close()\n\t\tconfirmationBytes = nil //nolint:ineffassign,wastedassign\n\t\tconn = nil              //nolint:wastedassign,ineffassign\n\t}\n","sourceCodeStart":288,"sourceCodeEnd":324,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/cmd/commandfuncs.go#L288-L324","documentation":"Returned by `caddy run --pingback` (the child of `caddy start`) when io.ReadAll(os.Stdin) fails while reading the confirmation bytes the parent wrote to the pipe. Failure means the stdin pipe was in a bad state — the parent died before/while writing, or stdin was closed/replaced by an incompatible descriptor.","triggerScenarios":"The parent `caddy start` process is killed between spawning the child and writing the 32 bytes; running `caddy run --pingback addr` manually without a parent providing stdin; stdin redirected to a directory or a closed FD.","commonSituations":"Almost exclusively internal to the caddy start/run handshake; manual use of the undocumented --pingback flag; OOM killers or supervisors killing the parent at the wrong moment.","solutions":["Do not invoke `caddy run --pingback` manually — it is reserved for the caddy start handshake","If seen during caddy start, check whether a supervisor/OOM killer terminated the parent; free memory and retry","Use `caddy run` directly for foreground operation"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// internal handshake flag: if you must run it, keep stdin open\n// err from caddy run --pingback containing 'reading confirmation bytes from stdin'\n// => parent pipe broken: ensure the parent (caddy start) stays alive or drop --pingback","preventionTips":["Never use the --pingback flag manually; it belongs to the caddy start handshake","Protect the parent process from OOM/signal races (memory limits, no aggressive kill timeouts)"],"tags":["cli","caddy-run","pingback","stdin","internal"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}