caddyserver/caddy · error
invalid socket file descriptor: %d
Error message
invalid socket file descriptor: %d
What it means
For 'fd'/'fdgram' listening, Caddy wraps the numeric descriptor with os.NewFile and caches it. If the resulting *os.File is nil (the descriptor could not be turned into a file object), this error reports the offending descriptor number. In practice this signals a descriptor that is not open or not a valid socket in the current process.
Source
Thrown at listen.go:61
func() {
socketFilesMu.Lock()
defer socketFilesMu.Unlock()
socketFdWide := uintptr(socketFd)
var ok bool
socketFile, ok = socketFiles[socketFdWide]
if !ok {
socketFile = os.NewFile(socketFdWide, lnKey)
if socketFile != nil {
socketFiles[socketFdWide] = socketFile
}
}
}()
if socketFile == nil {
return nil, fmt.Errorf("invalid socket file descriptor: %d", socketFd)
}
}
datagram := slices.Contains([]string{"udp", "udp4", "udp6", "unixgram", "fdgram"}, network)
if datagram {
sharedPc, _, err := listenerPool.LoadOrNew(lnKey, func() (Destructor, error) {
var (
pc net.PacketConn
err error
)
if fd {
pc, err = net.FilePacketConn(socketFile)
} else {
pc, err = config.ListenPacket(ctx, network, address)
}
if err != nil {
return nil, err
}View on GitHub (pinned to 50e54ee279)
Solutions
- Confirm the descriptor is actually open in this Caddy process (e.g. ls -l /proc/<pid>/fd).
- With systemd, use ListenFDs-style socket activation so the fd is inherited, and reference the correct index.
- If not using socket activation, switch to a normal tcp/unix listener instead of 'fd'.
- Restart Caddy after changing the supervisor's passed-socket set so numbering matches.
Example fix
// before (fd 3 not actually passed)
{
listen fd 3
}
// after
{
listen unix/run/caddy.sock
} Defensive patterns
Strategy: validation
Validate before calling
func fdOpen(fd uint64) bool {
_, err := unix.FcntlInt(unix.Fstat(int(fd))) // or os.NewFile check
return err == nil
} Prevention
- With systemd socket activation, derive fd numbers from LISTEN_FDS/LISTEN_PID env, not constants.
- Log open descriptors at startup when debugging fd-based listens.
When it happens
Trigger: listen fd with a number that is not an open descriptor in the Caddy process — e.g. it was closed, belongs to another process, or the value is out of range for open descriptors. os.NewFile returning nil for a bad fd is the trigger.
Common situations: Hardcoding an fd number that shifts when the supervisor changes; running Caddy without systemd socket activation while the config assumes it; double-use of a descriptor that was already consumed and closed by an earlier config reload.
Related errors
- invalid socket file descriptor: %d
- invalid file descriptor: %v
- invalid file descriptor: %v
- parsing browse template: %v
- no permission module configured; certificates not allowed ex
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/73fac88eedaabf5e.
Report an issue: GitHub.