caddyserver/caddy · error · errUnixSocketAlreadyInUse
cannot reuse socket %v: %w
Error message
cannot reuse socket %v: %w
What it means
On Windows, before binding a unix socket Caddy probes the path with a 10ms dial to see if a live server owns it. If the dial succeeds (err == nil), another process is actively serving on that socket, so Caddy refuses to reuse it — the error wraps errUnixSocketAlreadyInUse even though the dial itself succeeded.
Source
Thrown at listen_reuseUnixSocket_windows.go:62
// Abstract Unix sockets do not require us to remove stale socket files.
return nil, nil
}
// On Windows, we're using the `fakeCloseListener` wrappers around a single, ever-living listener.
// So, if there's an active listener entry in the pool, we're the current owner of the Unix socket file.
_, socketBelongsToCurrentProcess := listenerPool.References(listenerKey(network, addr))
if socketBelongsToCurrentProcess {
// Reuse/cleanup is entirely handled by the refcounting mechanism in `listenerPool`.
return nil, nil
}
// If the socket file does not exist or has no backing server process, this will fail instantly.
connection, err := net.DialTimeout("unix", addr, 10*time.Millisecond)
if err == nil {
connection.Close()
return nil, fmt.Errorf("cannot reuse socket %v: %w", addr, errUnixSocketAlreadyInUse)
}
// Windows returns this error code both if the socket file does not exist and if it isn't backed by a server process anymore.
// See: https://learn.microsoft.com/en-us/windows/win32/winsock/windows-sockets-error-codes-2#wsaeconnrefused
const WSAECONNREFUSED syscall.Errno = 10061
var errno syscall.Errno
hasNoListeningServerProcess := errors.As(err, &errno) && errno == WSAECONNREFUSED
if !hasNoListeningServerProcess {
return nil, fmt.Errorf("cannot reuse socket %v: %w", addr, errUnixSocketAlreadyInUse)
}
// If the socket file exists, it hasn't been created by our process, and it seemingly
// isn't backed by a server process anymore. Try to delete it so we can bind to it later.
err = os.Remove(addr)
if err == nil {View on GitHub (pinned to 50e54ee279)
Solutions
- Stop the other process listening on that socket path, then start Caddy again.
- Point the new instance at a different socket path.
- On Windows, check with Get-Process / handle.exe to find the process holding the file.
Defensive patterns
Strategy: fallback
Try / catch
if err := srv.Start(ctx); err != nil {
if strings.Contains(err.Error(), "cannot reuse socket") {
// pick alternate path or terminate the other instance
}
} Prevention
- Give each Caddy instance its own socket path via unique names or runtime dirs.
- Ensure supervising systems stop old processes before starting replacements.
When it happens
Trigger: Two Caddy instances (or a Caddy and another AF_UNIX server on Windows) configured with the same unix socket path where the other process is alive and accepting; also a leftover process from a previous run that never exited.
Common situations: Starting a second Caddy with the same config on Windows; a zombie/old process still holding the socket; a test harness that starts overlapping servers on the same path.
Related errors
- unable to set permissions (%s) on %s: %v
- could not parse octal permission bits in %s: %v
- owner of the socket requires '-w-' (write, octal: '2') permi
- invalid file descriptor: %v
- invalid file descriptor: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/fc3351a5afacfae6.
Report an issue: GitHub.