gofiber/fiber · critical

prefork

Error message

prefork: %w

What it means

Thrown when the prefork master process's ListenAndServe(addr) fails. Prefork uses SO_REUSEPORT to run multiple child listeners; the master must itself bind the address. The %w wraps the underlying listener/bind error. This is fatal to server startup — if the master cannot listen, no children serve.

Solutions

  1. Free or change the port (the wrapped error is usually EADDRINUSE / EACCES — read it).
  2. Run with privileges for ports <1024, or use a non-privileged port plus setcap/sudo/iptables redirect.
  3. Disable prefork on platforms without SO_REUSEPORT support.
  4. Validate the address format and ListenerNetwork before calling Listen with Prefork: true.
  5. Check the container/host port binding.

Example fix

// before
app.Listen(":80", fiber.ListenConfig{Prefork: true}) // EACCES or EADDRINUSE -> prefork: ...

// after
addr := ":8080"
ln, err := net.Listen("tcp", addr)
if err != nil { log.Fatalf("cannot bind %s: %v", addr, err) }
ln.Close()
app.Listen(addr, fiber.ListenConfig{Prefork: true})
Defensive patterns

Strategy: validation

Validate before calling

// Probe-bind before starting prefork to get a clear, early failure.
func checkListen(addr, network string) error {
    ln, err := net.Listen(network, addr)
    if err != nil { return err }
    return ln.Close()
}
// also guard privileges for low ports
func canBindLowPort(port int) bool {
    return port >= 1024 || os.Geteuid() == 0
}

Type guard

func addrLikelyBindable(addr string) bool {
    _, portStr, err := net.SplitHostPort(addr)
    if err != nil { return false }
    port, _ := strconv.Atoi(portStr)
    return port >= 1024 || os.Geteuid() == 0
}

Try / catch

if err := checkListen(addr, cfg.ListenerNetwork); err != nil {
    log.Fatalf("prefork pre-bind check failed for %s: %v", addr, err)
}
if err := app.Listen(addr, fiber.ListenConfig{Prefork: true}); err != nil {
    log.Fatalf("prefork: %v", err)
}

Prevention

When it happens

Trigger: The address is already bound by another process (EADDRINUSE); binding a privileged port (<1024) without sufficient privileges (EACCES); SO_REUSEPORT unsupported on the platform/older kernel; an invalid/already-resolved address; listener creation failure; the network value in ListenConfig is invalid.

Common situations: Another server already on the port; running as non-root on :80/:443; older Windows or kernels without SO_REUSEPORT; misformed host:port in app.Listen(..., prefork); running inside a container whose port is already bound at the host level.

Related errors


AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11). Data as JSON: /api/errors/abd0b523081de13a. Report an issue: GitHub.

Appendix: source

Thrown at prefork.go:116

		}
		return nil
	}

	// Master callback: all children spawned → startup message & OnListen hooks
	p.OnMasterReady = func(childPIDs []int) error {
		listenData := app.prepareListenData(addr, tlsConfig != nil, cfg, childPIDs)
		app.runOnListenHooks(listenData)
		app.printMessages(cfg, listenData)
		return nil
	}

	// Master callback: child recovered after crash
	p.OnChildRecover = func(oldPID, newPID int) {
		logger.Printf("prefork: child %d crashed, recovered with new PID %d", oldPID, newPID)
	}

	if err := p.ListenAndServe(addr); err != nil {
		return fmt.Errorf("prefork: %w", err)
	}

	return nil
}

// dummyCmd is for internal prefork testing
func dummyCmd() *exec.Cmd {
	command := "go"
	if storeCommand := dummyChildCmd.Load(); storeCommand != nil && storeCommand != "" {
		command = storeCommand.(string) //nolint:forcetypeassert,errcheck // We always store a string in here
	}
	if runtime.GOOS == windowsOS {
		return exec.Command("cmd", "/C", command, "version")
	}
	return exec.Command(command, "version")
}

View on GitHub (pinned to a105acad6c)