dotnet/runtime · error
dup2(stderr) failed: %s\n
Error message
dup2(stderr) failed: %s\n
What it means
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.
Source
Thrown at src/coreclr/tools/superpmi/superpmi/parallelsuperpmi.cpp:220
{
LogError("fork() failed: %s", strerror(errno));
for (int i = 0; i < argc; i++)
delete[] argv[i];
delete[] argv;
return false;
}
if (*pid == 0)
{
// Child process: redirect stdout and stderr then exec.
if (dup2(hStdOutput, STDOUT_FILENO) == -1)
{
fprintf(stderr, "dup2(stdout) failed: %s\n", strerror(errno));
_exit(1);
}
if (dup2(hStdError, STDERR_FILENO) == -1)
{
fprintf(stderr, "dup2(stderr) failed: %s\n", strerror(errno));
_exit(1);
}
// Close the original fds now that they are duplicated to STDOUT/STDERR.
// The O_CLOEXEC on the parent's open() handles the sibling worker fds.
if (hStdOutput != STDOUT_FILENO)
close(hStdOutput);
if (hStdError != STDERR_FILENO)
close(hStdError);
execv(argv[0], argv);
// If execv returns, it failed.
fprintf(stderr, "execv(%s) failed: %s\n", argv[0], strerror(errno));
_exit(1);
}
// Parent process: free argv and return.
for (int i = 0; i < argc; i++)View on GitHub (pinned to 60108ba66e)
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.
Defensive patterns
Strategy: validation
Validate before calling
// Same fd-limit discipline as stdout; both pipes must fit.
#include <sys/resource.h>
static bool RaiseFdLimit(rlim_t want) {
struct rlimit r;
if (getrlimit(RLIMIT_NOFILE, &r) != 0) return false;
if (r.rlim_cur >= want) return true;
r.rlim_cur = want < r.rlim_max ? want : r.rlim_max;
return setrlimit(RLIMIT_NOFILE, &r) == 0;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- dup2(stdout) failed: %s\n
- execv(%s) failed: %s\n
- Error: Fail to PAL_Initialize\n
- Error: Fail to PAL_InitializeDLL\n
- Error: Fail to PAL_InitializeDLL\n
AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10).
Data as JSON: /api/errors/6b0a443dd45f602c.
Report an issue: GitHub.