caddyserver/caddy · warning

cannot reuse socket %v: unix socket is already in use by ano

Error message

cannot reuse socket %v: unix socket is already in use by another process

What it means

During ECH key rotation, a config older than rotationInterval (30 days) with no Replaced timestamp needed a replacement, and generateAndStoreECHConfig failed — it could not generate an ECH keypair/config for the public name or persist it to storage.

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. Check the wrapped error from generateAndStoreECHConfig for the exact failing step.
  2. Ensure writable storage and adequate disk space on all instances.
  3. Fix backend connectivity; rotation retries on the next maintenance tick.
  4. If config ID collisions are indicated in a cluster, ensure all instances share one storage backend so ID allocation is serialized by the ech_rotation lock.
Defensive patterns

Strategy: retry

Try / catch

Retry on next rotation tick after fixing storage; if generation itself fails (rare), capture the inner error and report upstream.

Prevention

When it happens

Trigger: generateAndStoreECHConfig: HPKE key generation failure (extremely rare), finding a free config ID via storage trial paths failing, or storage.Store of key.bin/config.bin/meta.json under ech/configs/<id> failing (read-only, full disk, backend outage).

Common situations: Data volume full or read-only after 30 days of uptime when rotation first triggers; storage credentials expiring; a cluster peer holding conflicting config IDs due to divergent storage views.

Related errors


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