valyala/fasthttp · warning

prefork: close inherited listener fd: %w

Error message

prefork: close inherited listener fd: %w

What it means

In fasthttp's prefork child process (listen called from listenAsChild), the inherited listener FD is wrapped via os.NewFile and converted with net.FileListener; the wrapping *os.File is then closed to avoid leaking the original descriptor. If that Close fails, the error is wrapped as 'prefork: close inherited listener fd'. The listener itself owns a dup'd fd and remains usable; this signals an fd bookkeeping problem in the child process.

Source

Thrown at prefork/prefork.go:274

	if p.Network == "" {
		p.Network = defaultNetwork
	}

	if p.Reuseport {
		return reuseport.Listen(p.Network, addr)
	}

	// fd inheritedListenerFD is the first ExtraFiles entry passed by the
	// master process when Reuseport is false. Naming the file gives clearer
	// errors from net.FileListener if the fd is invalid.
	//
	// net.FileListener dups the fd, so we close the wrapping *os.File after
	// it returns to avoid leaking the original descriptor. The returned
	// listener owns its own dup'd fd and is unaffected by this close.
	f := os.NewFile(inheritedListenerFD, "fasthttp-prefork-listener")
	ln, err := net.FileListener(f)
	if closeErr := f.Close(); closeErr != nil && err == nil {
		err = fmt.Errorf("prefork: close inherited listener fd: %w", closeErr)
	}
	if err != nil {
		if ln != nil {
			_ = ln.Close()
		}
		return nil, err
	}
	return ln, nil
}

// listenAsChild performs the common child process setup: creates the listener
// and starts watching the master process if OnMasterDeath is configured.
func (p *Prefork) listenAsChild(addr string) (net.Listener, error) {
	ln, err := p.listen(addr)
	if err != nil {
		return nil, err
	}

View on GitHub (pinned to c96f600972)

Solutions

  1. Update fasthttp — recent versions hardened this path; verify you are on a current release.
  2. Check the environment: run without sandbox/restrictions or adjust seccomp profiles to allow standard fd syscalls.
  3. Ensure nothing else closes or reuses the inherited listener FD before prefork's listen runs.
  4. As a fallback, disable prefork if your deployment doesn't need multi-process socket sharing.

Example fix

// before
// prefork enabled inside a restricted sandbox
panic(fasthttp.Prefork(serv, handler))
// after
if os.Getenv("SANDBOXED") == "1" {
    // skip prefork in restricted environments
    panic(fasthttp.Serve(ln, handler))
}
Defensive patterns

Strategy: fallback

Validate before calling

// Before enabling prefork in constrained environments, verify fd ops work:
f := os.NewFile(3, "probe")
if f != nil {
    if err := f.Close(); err != nil {
        log.Printf("fd close unavailable in this sandbox: %v", err)
    }
}

Type guard

func preforkSupported() bool {
    return runtime.GOOS != "windows" && os.Getenv("SANDBOXED") != "1"
}

Try / catch

// top-level:
if err := run(); err != nil {
    if strings.Contains(err.Error(), "close inherited listener fd") {
        log.Printf("prefork fd issue, falling back to single process: %v", err)
        return serveWithoutPrefork()
    }
    return err
}

Prevention

When it happens

Trigger: Running with prefork enabled and the child calling f.Close() on the inherited listener file after net.FileListener — Close fails e.g. due to an invalid fd, fd already closed, or sandbox environments restricting fd operations.

Common situations: Containers/sandboxes (gVisor, restricted seccomp) where close(2) on inherited fds misbehaves; running prefork under supervisors that pass unexpected fd state; custom code touching the inherited FD before prefork listens.

Related errors


AI-assisted analysis of valyala/fasthttp@c96f600972 (2026-08-31). Data as JSON: /api/errors/14309e9bde0184ee. Report an issue: GitHub.