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

  1. Stop the other process listening on that socket path, then start Caddy again.
  2. Point the new instance at a different socket path.
  3. 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

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


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/fc3351a5afacfae6. Report an issue: GitHub.