{"record":{"id":"6e437190cd983f3d","repo":"dotnet/runtime","slug":"problem-writing-to-createdump-parent-write-pipe","errorCode":null,"errorMessage":"Problem writing to createdump parent_write_pipe: %s (%d)\\n","messagePattern":"Problem writing to createdump parent_write_pipe: (.+?) \\((.+?)\\)\\\\n","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/coreclr/nativeaot/Runtime/unix/PalCreateDump.cpp","lineNumber":304,"sourceCode":"#if HAVE_PRCTL_H && HAVE_PR_SET_PTRACER\n        // Gives the child process permission to use /proc/<pid>/mem and ptrace\n        if (prctl(PR_SET_PTRACER, childpid, 0, 0, 0) == -1)\n        {\n            // Ignore any error because on some CentOS and OpenSUSE distros, it isn't\n            // supported but createdump works just fine.\n#ifdef _DEBUG\n            fprintf(stderr, \"CreateCrashDump: prctl() FAILED %s (%d)\\n\", strerror(errno), errno);\n#endif\n        }\n#endif // HAVE_PRCTL_H && HAVE_PR_SET_PTRACER\n        // Signal child that prctl(PR_SET_PTRACER, childpid) is done\n        int bytesWritten;\n        while((bytesWritten = write(parent_write_pipe, \"S\", 1)) < 0 && errno == EINTR);\n        close(parent_write_pipe);\n\n        if (bytesWritten != 1)\n        {\n            fprintf(stderr, \"Problem writing to createdump parent_write_pipe: %s (%d)\\n\", strerror(errno), errno);\n            close(parent_read_pipe);\n            if (errorMessageBuffer != nullptr)\n            {\n                errorMessageBuffer[0] = 0;\n            }\n            return false;\n        }\n\n        // Read createdump's stderr messages (if any)\n        if (errorMessageBuffer != nullptr)\n        {\n            // Read createdump's stderr\n            int bytesRead = 0;\n            int count = 0;\n            while ((count = read(parent_read_pipe, errorMessageBuffer + bytesRead, cbErrorMessageBuffer - bytesRead)) > 0)\n            {\n                bytesRead += count;\n            }","sourceCodeStart":286,"sourceCodeEnd":322,"githubUrl":"https://github.com/dotnet/runtime/blob/290d5ab72cc1102813fbc0406fb186ceadabc340/src/coreclr/nativeaot/Runtime/unix/PalCreateDump.cpp#L286-L322","documentation":"Emitted from the NativeAOT parent process in CreateCrashDump (PalCreateDump.cpp:304). After fork, the parent runs prctl(PR_SET_PTRACER, childpid) then writes a single 'S' byte through parent_write_pipe to release the child from its blocking read(); the write() is retried only on EINTR. If the final byte count is not 1 the parent prints this message, clears the error buffer, closes parent_read_pipe and returns false, so no dump is produced. The near-universal cause is a broken pipe: the child has already exited and closed its read end, so write() returns -1 with EPIPE.","triggerScenarios":"DOTNET_DbgEnableMiniDump=1 is set and the process crashes; the forked child dies during setup (for example it hit the 'Problem reading from createdump child_read_pipe' branch at line 258 and called exit(-1)) before the parent's write() completes. It can also fire if the parent itself is interrupted (signal) such that the write returns 0 or a non-EINTR error, or if the pipe fds were invalidated.","commonSituations":"Child perished first because the child_read_pipe read failed (parent never wrote, or parent died in the prctl path); the process was SIGKILLed by the OOM killer or a container reaper between fork and the parent's write; a custom SIGCHLD reaper or signal handler interfered; resource exhaustion (fd limit) left the pipe half-open.","solutions":["Collect full createdump diagnostics first: set DOTNET_CreateDumpDiagnostics=1 and DOTNET_CreateDumpVerboseDiagnostics=1 and reproduce; the child's earlier 'Problem reading ... child_read_pipe' line is the real root cause.","Check whether the process is being killed externally during crash handling (dmesg for oom-killer, container runtime OOM events) and raise memory limits or disable the reaper.","Ensure no third-party SIGCHLD handler / init system (e.g. dumb-init, tini in PID-1 reap mode) is reaping the createdump child before the parent writes.","Raise the open-files limit (ulimit -n) if the crash path is running out of pipe fds.","If the environment cannot support out-of-proc dumps, unset DOTNET_DbgEnableMiniDump and rely on the OS core pattern (coredumpd/apport) instead."],"exampleFix":"# before\n$ DOTNET_DbgEnableMiniDump=1 ./app\n# Problem writing to createdump parent_write_pipe: Broken pipe (32)\n\n# after: enable diagnostics to see the child's preceding failure\n$ DOTNET_DbgEnableMiniDump=1 \\\n  DOTNET_CreateDumpDiagnostics=1 \\\n  DOTNET_CreateDumpVerboseDiagnostics=1 \\\n  ./app","handlingStrategy":"validation","validationCode":"# Before relying on minidumps, verify the crash path can keep the parent/child pipe alive.\n[ \"$(ulimit -n)\" -ge 1024 ] || ulimit -n 65536\n# Ensure no PID-1 reaper will steal or kill the child; if using --init, test dump capture once:\nDOTNET_DbgEnableMiniDump=1 DOTNET_CreateDumpVerboseDiagnostics=1 ./app & sleep 1; kill -ABRT $!; wait $!\nls -l *.dmp 2>/dev/null || echo \"WARN: dump handshake unreliable in this environment\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always enable DOTNET_CreateDumpDiagnostics=1 / DOTNET_CreateDumpVerboseDiagnostics=1 during dump-path validation so the real upstream failure (usually the child_read_pipe read) is visible.","Do not run under an aggressive PID-1 child reaper when minidumps are required.","Raise ulimit -n and cgroup memory limits so the crash path has the fds/memory for the pipe handshake.","Prefer the OS core_pattern for production crash capture and treat DOTNET_DbgEnableMiniDump as a secondary mechanism."],"tags":["dotnet","nativeaot","createdump","crash-dump","pipe","diagnostics","linux"],"analyzedSha":"290d5ab72cc1102813fbc0406fb186ceadabc340","analyzedAt":"2026-08-06T19:57:01.276Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}