{"record":{"id":"6b0a443dd45f602c","repo":"dotnet/runtime","slug":"dup2-stderr-failed-s-n","errorCode":null,"errorMessage":"dup2(stderr) failed: %s\\n","messagePattern":"dup2\\(stderr\\) failed: (.+?)\\\\n","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/coreclr/tools/superpmi/superpmi/parallelsuperpmi.cpp","lineNumber":220,"sourceCode":"    {\n        LogError(\"fork() failed: %s\", strerror(errno));\n        for (int i = 0; i < argc; i++)\n            delete[] argv[i];\n        delete[] argv;\n        return false;\n    }\n\n    if (*pid == 0)\n    {\n        // Child process: redirect stdout and stderr then exec.\n        if (dup2(hStdOutput, STDOUT_FILENO) == -1)\n        {\n            fprintf(stderr, \"dup2(stdout) failed: %s\\n\", strerror(errno));\n            _exit(1);\n        }\n        if (dup2(hStdError, STDERR_FILENO) == -1)\n        {\n            fprintf(stderr, \"dup2(stderr) failed: %s\\n\", strerror(errno));\n            _exit(1);\n        }\n\n        // Close the original fds now that they are duplicated to STDOUT/STDERR.\n        // The O_CLOEXEC on the parent's open() handles the sibling worker fds.\n        if (hStdOutput != STDOUT_FILENO)\n            close(hStdOutput);\n        if (hStdError != STDERR_FILENO)\n            close(hStdError);\n\n        execv(argv[0], argv);\n        // If execv returns, it failed.\n        fprintf(stderr, \"execv(%s) failed: %s\\n\", argv[0], strerror(errno));\n        _exit(1);\n    }\n\n    // Parent process: free argv and return.\n    for (int i = 0; i < argc; i++)","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/dotnet/runtime/blob/60108ba66eb7d1d12f595480091b4ad80a24b172/src/coreclr/tools/superpmi/superpmi/parallelsuperpmi.cpp#L202-L238","documentation":"Symmetrical to the stdout case: the forked ParallelSuperPMI child redirects stderr to a captured pipe with dup2(hStdError,STDERR_FILENO). A -1 return prints this message with strerror(errno) and the child _exit(1)s. It is the second redirection, attempted only after stdout dup2 succeeded.","triggerScenarios":"hStdError is not a valid open descriptor or the process is out of file descriptors (EMFILE); the stderr pipe handle was closed or invalidated before the child runs dup2. Child-side fatal during worker startup.","commonSituations":"Per-process fd exhaustion when spawning many workers (each worker holds stdout+stderr pipes); a race closing the stderr pipe before fork completes; an upstream open() failure for the stderr pipe that was not checked.","solutions":["Increase ulimit -n so the combined stdout+stderr pipes for all workers fit.","Lower the worker count (-j/--workers).","Verify the code that opens hStdError surfaces open() failures rather than passing INVALID_HANDLE_VALUE into dup2.","strace -f -e dup2 to capture the exact errno and descriptor."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Same fd-limit discipline as stdout; both pipes must fit.\n#include <sys/resource.h>\nstatic bool RaiseFdLimit(rlim_t want) {\n    struct rlimit r;\n    if (getrlimit(RLIMIT_NOFILE, &r) != 0) return false;\n    if (r.rlim_cur >= want) return true;\n    r.rlim_cur = want < r.rlim_max ? want : r.rlim_max;\n    return setrlimit(RLIMIT_NOFILE, &r) == 0;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Account for both stdout and stderr pipes per worker when sizing the fd limit.","Validate the stderr pipe handle before fork so dup2 receives a valid fd.","Reduce worker count if the limit cannot be raised.","strace -f -e dup2 to pinpoint the failing stderr redirect."],"tags":["superpmi","parallelsuperpmi","dup2","fork","file-descriptors","unix"],"backgroundTag":null,"analyzedSha":"60108ba66eb7d1d12f595480091b4ad80a24b172","analyzedAt":"2026-08-10T18:54:11.478Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}