valyala/fasthttp · error
prefork: dup listener fd: %w
Error message
prefork: dup listener fd: %w
What it means
Returned by Prefork.setTCPListenerFiles when tcpListenerFile (which calls the listener's File() to duplicate the socket fd) fails. The bound listener is explicitly closed first so no socket/fd leaks. This means the OS refused to duplicate the listener's file descriptor, which prefork needs to pass to child processes.
Source
Thrown at prefork/prefork.go:323
}
tcpAddr, err := net.ResolveTCPAddr(p.Network, addr)
if err != nil {
return fmt.Errorf("prefork: resolve %s/%s: %w", p.Network, addr, err)
}
tcpListener, err := net.ListenTCP(p.Network, tcpAddr)
if err != nil {
return fmt.Errorf("prefork: listen tcp %s: %w", addr, err)
}
listenerFile, err := tcpListenerFile(tcpListener)
if err != nil {
// Close the bound listener so we don't leak the socket/fd when
// File() fails. p.ln is intentionally only assigned after this
// point so the caller never sees a half-initialised state.
_ = tcpListener.Close()
return fmt.Errorf("prefork: dup listener fd: %w", err)
}
p.ln = tcpListener
p.files = []*os.File{listenerFile}
return nil
}
// childEnv returns os.Environ() with the prefork child marker variable set,
// stripping any pre-existing value to avoid duplicate keys with last-wins
// semantics.
func childEnv() []string {
src := os.Environ()
out := make([]string, 0, len(src)+1)
prefix := preforkChildEnvVariable + "="
for _, kv := range src {
if len(kv) >= len(prefix) && kv[:len(prefix)] == prefix {
continueView on GitHub (pinned to c96f600972)
Solutions
- Raise the file-descriptor limit: ulimit -n or systemd LimitNOFILE.
- Check for fd leaks in the process (lsof -p <pid> | wc -l).
- Retry after verifying the environment allows fcntl(F_DUPFD_CLOEXEC); inspect the wrapped error for the exact syscall failure.
- Update the library if using an OS/environment with known File() quirks on the runtime version.
Example fix
// before # container with default low limit // after # docker run --ulimit nofile=65536:65536 ...
Defensive patterns
Strategy: validation
Validate before calling
// Pre-flight: ensure the process can allocate fds
var lim syscall.Rlimit
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &lim); err != nil || lim.Cur < 1024 {
log.Printf("warning: low RLIMIT_NOFILE: %v (cur=%d)", err, lim.Cur)
} Try / catch
if err := p.Listen(addr); err != nil {
if strings.Contains(err.Error(), "dup listener fd") {
log.Fatalf("fd duplication failed (check ulimit -n): %v", err)
}
log.Fatalf("prefork failed: %v", err)
} Prevention
- Set generous RLIMIT_NOFILE in systemd/Docker (nofile=65536).
- Monitor open fd counts in production.
- Avoid running under sandboxes that block fcntl duplication.
- Test prefork startup in a staging environment matching production limits.
When it happens
Trigger: net.TCPListener.File() returning an error — typically when the underlying fd is invalid/closed, or resource limits (RLIMIT_NOFILE) prevent creating a new fd. Triggered inside prefork setup after a successful ListenTCP.
Common situations: File-descriptor exhaustion on the host (ulimit -n too low for the app's open files/sockets); running in restricted environments (some sandboxes/seccomp setups) where dup fcntl calls are blocked.
Related errors
- prefork: close inherited listener fd: %w
- prefork: listen tcp %s: %w
- prefork: command producer: %w
- prefork: resolve executable: %w
- prefork: start child %q: %w
AI-assisted analysis of valyala/fasthttp@c96f600972 (2026-08-31).
Data as JSON: /api/errors/c28b5a3d69def4df.
Report an issue: GitHub.