valyala/fasthttp · error

cannot determine backlog to pass to listen(2): %w

Error message

cannot determine backlog to pass to listen(2): %w

What it means

tcplisten wraps the raw listen(2) syscall to create reusable, deferred-accept TCP listeners. When cfg.Backlog is not set (<=0), fdSetup reads the kernel's somaxconn value to derive a backlog; if that lookup fails, it cannot call listen(2) and returns this error wrapping the cause. It surfaces from NewListener.

Source

Thrown at tcplisten/tcplisten.go:129

		if err = enableDeferAccept(fd); err != nil {
			return err
		}
	}

	if cfg.FastOpen {
		if err = enableFastOpen(fd); err != nil {
			return err
		}
	}

	if err = unix.Bind(fd, sa); err != nil {
		return fmt.Errorf("cannot bind to %q: %w", addr, err)
	}

	backlog := cfg.Backlog
	if backlog <= 0 {
		if backlog, err = soMaxConn(); err != nil {
			return fmt.Errorf("cannot determine backlog to pass to listen(2): %w", err)
		}
	}
	if err = unix.Listen(fd, backlog); err != nil {
		return fmt.Errorf("cannot listen on %q: %w", addr, err)
	}

	return nil
}

func getSockaddr(network, addr string) (sa unix.Sockaddr, soType int, err error) {
	tcpAddr, err := net.ResolveTCPAddr(network, addr)
	if err != nil {
		return nil, -1, err
	}

	switch network {
	case "tcp4":
		var sa4 unix.SockaddrInet4

View on GitHub (pinned to c96f600972)

Solutions

  1. Set an explicit Backlog (>0) in the tcplisten.Config so soMaxConn() is never called
  2. Check /proc/sys/net/core/somaxconn is readable by the process user (cat it manually)
  3. Relax container/seccomp or AppArmor restrictions on /proc/sys reads
  4. Check the wrapped %w error for the underlying read failure

Example fix

// before
cfg := tcplisten.Config{ReusePort: true} // Backlog unset -> procfs lookup
ln, err := tcplisten.NewListener(cfg, "tcp", ":8080")
// after
cfg := tcplisten.Config{ReusePort: true, Backlog: 1024} // explicit backlog skips somaxconn lookup
ln, err := tcplisten.NewListener(cfg, "tcp", ":8080")
Defensive patterns

Strategy: validation

Validate before calling

func backlogConfigured(cfg tcplisten.Config) bool { return cfg.Backlog > 0 }
if !backlogConfigured(cfg) {
    if b, err := ioutil.ReadFile("/proc/sys/net/core/somaxconn"); err != nil && !os.IsNotExist(err) {
        cfg.Backlog = 1024 // avoid procfs-dependent lookup
    }
}

Try / catch

ln, err := tcplisten.NewListener(cfg, network, addr)
if err != nil {
    var sysErr *fs.PathError
    if errors.As(err, &sysErr) || strings.Contains(err.Error(), "somaxconn") {
        cfg.Backlog = 1024
        ln, err = tcplisten.NewListener(cfg, network, addr)
    }
}

Prevention

When it happens

Trigger: Calling tcplisten.NewListener with a Config whose Backlog is 0 or negative on Linux when soMaxConn() fails — i.e. /proc/sys/net/core/somaxconn exists but cannot be read due to permissions/other I/O error (a missing file is tolerated and falls back to unix.SOMAXCONN).

Common situations: Hardened containers/seccomp profiles blocking reads from /proc; pseudo-filesystems where /proc/sys is read-restricted or returns other I/O errors; unusual environments (some CI sandboxes) where the procfs file is present but unreadable.

Related errors


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