{"record":{"id":"fc3351a5afacfae6","repo":"caddyserver/caddy","slug":"cannot-reuse-socket-v-w","errorCode":null,"errorMessage":"cannot reuse socket %v: %w","messagePattern":"cannot reuse socket (.+?): %w","errorType":"exception","errorClass":"errUnixSocketAlreadyInUse","httpStatus":null,"severity":"error","filePath":"listen_reuseUnixSocket_windows.go","lineNumber":62,"sourceCode":"\t\t// Abstract Unix sockets do not require us to remove stale socket files.\n\t\treturn nil, nil\n\t}\n\n\t// On Windows, we're using the `fakeCloseListener` wrappers around a single, ever-living listener.\n\t// So, if there's an active listener entry in the pool, we're the current owner of the Unix socket file.\n\t_, socketBelongsToCurrentProcess := listenerPool.References(listenerKey(network, addr))\n\n\tif socketBelongsToCurrentProcess {\n\t\t// Reuse/cleanup is entirely handled by the refcounting mechanism in `listenerPool`.\n\t\treturn nil, nil\n\t}\n\n\t// If the socket file does not exist or has no backing server process, this will fail instantly.\n\tconnection, err := net.DialTimeout(\"unix\", addr, 10*time.Millisecond)\n\n\tif err == nil {\n\t\tconnection.Close()\n\t\treturn nil, fmt.Errorf(\"cannot reuse socket %v: %w\", addr, errUnixSocketAlreadyInUse)\n\t}\n\n\t// Windows returns this error code both if the socket file does not exist and if it isn't backed by a server process anymore.\n\t// See: https://learn.microsoft.com/en-us/windows/win32/winsock/windows-sockets-error-codes-2#wsaeconnrefused\n\tconst WSAECONNREFUSED syscall.Errno = 10061\n\n\tvar errno syscall.Errno\n\thasNoListeningServerProcess := errors.As(err, &errno) && errno == WSAECONNREFUSED\n\n\tif !hasNoListeningServerProcess {\n\t\treturn nil, fmt.Errorf(\"cannot reuse socket %v: %w\", addr, errUnixSocketAlreadyInUse)\n\t}\n\n\t// If the socket file exists, it hasn't been created by our process, and it seemingly\n\t// isn't backed by a server process anymore. Try to delete it so we can bind to it later.\n\terr = os.Remove(addr)\n\n\tif err == nil {","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/listen_reuseUnixSocket_windows.go#L44-L80","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := srv.Start(ctx); err != nil {\n    if strings.Contains(err.Error(), \"cannot reuse socket\") {\n        // pick alternate path or terminate the other instance\n    }\n}","preventionTips":["Give each Caddy instance its own socket path via unique names or runtime dirs.","Ensure supervising systems stop old processes before starting replacements."],"tags":["unix-socket","windows","port-conflict","listen"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}