{"id":"5ab24ffa8733ca8a","repo":"gofiber/fiber","slug":"unexpected-error-when-trying-to-remove-unix-socket","errorCode":null,"errorMessage":"unexpected error when trying to remove unix socket file %q: %w","messagePattern":"unexpected error when trying to remove unix socket file %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"listen.go","lineNumber":373,"sourceCode":"\tif cfg.EnablePrefork {\n\t\tlog.Warn(\"Prefork isn't supported for custom listeners.\")\n\t}\n\n\treturn app.server.Serve(ln)\n}\n\n// Create listener function.\nfunc (*App) createListener(addr string, tlsConfig *tls.Config, cfg *ListenConfig) (net.Listener, error) {\n\tif cfg == nil {\n\t\tcfg = &ListenConfig{}\n\t}\n\tvar listener net.Listener\n\tvar err error\n\n\t// Remove previously created socket, to make sure it's possible to listen\n\tif cfg.ListenerNetwork == NetworkUnix {\n\t\tif err = os.Remove(addr); err != nil && !os.IsNotExist(err) {\n\t\t\treturn nil, fmt.Errorf(\"unexpected error when trying to remove unix socket file %q: %w\", addr, err)\n\t\t}\n\t}\n\n\tif tlsConfig != nil {\n\t\tlistener, err = tls.Listen(cfg.ListenerNetwork, addr, tlsConfig)\n\t} else {\n\t\tlistener, err = net.Listen(cfg.ListenerNetwork, addr)\n\t}\n\n\t// Check for error before using the listener\n\tif err != nil {\n\t\t// Wrap the error from tls.Listen/net.Listen\n\t\treturn nil, fmt.Errorf(\"failed to listen: %w\", err)\n\t}\n\n\tif cfg.ListenerNetwork == NetworkUnix {\n\t\tif err = os.Chmod(addr, cfg.UnixSocketFileMode); err != nil {\n\t\t\t_ = listener.Close() //nolint:errcheck // best-effort cleanup on the error path","sourceCodeStart":355,"sourceCodeEnd":391,"githubUrl":"https://github.com/gofiber/fiber/blob/9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c/listen.go#L355-L391","documentation":"Emitted by createListener when ListenerNetwork is 'unix' and os.Remove of the configured socket path returns an error other than os.ErrNotExist. Fiber proactively clears a stale socket before binding so a crashed/restarting process can re-claim the address; any removal error that is NOT 'file does not exist' is treated as fatal because the subsequent net.Listen would almost certainly fail too. The wrapped %w preserves the underlying syscall error (EACCES, EISDIR, EBUSY, etc.).","triggerScenarios":"Starting Fiber with app.Listen(NetworkUnix+'/var/run/app.sock', ...) where the path exists and is owned by another uid (EACCES), is a directory (EISDIR), or is held open by a still-running process you don't have permission to unlink. Removing a path on a read-only filesystem or in a directory without write permission also triggers it.","commonSituations":"Two instances pointed at the same socket where the second lacks privileges; running under a non-root user while the prior run was root (root-owned socket); systemd socket activation leaves a socket file; Docker volume mounted read-only; path typo resolves to an existing directory.","solutions":["Identify and stop the prior holder: 'lsof <path>' or 'fuser <path>' then kill the PID, or stop the systemd unit.","Fix ownership/permissions so the current process can remove the file: 'sudo chown $(id -u):$(id -g) <path>' or 'sudo rm <path>'.","Verify the path is a file/socket and not a directory: 'ls -ld <path>' — if 'd', pick a different path.","Ensure the parent directory is writable and not on a read-only mount: 'touch <parent>/__t && rm <parent>/__t'.","Restart the service so createListener can os.Remove cleanly."],"exampleFix":"// before: stale root-owned socket blocks the non-root restart\n_ = app.Listen(\"/var/run/app.sock\", fiber.ListenConfig{\n  ListenerNetwork: fiber.NetworkUnix,\n})\n\n// after: own and clean the path before start, or use a runtime-writable dir\nos.Remove(\"/run/user/app/app.sock\") // best-effort; ignore IsNotExist\n_ = app.Listen(\"/run/user/app/app.sock\", fiber.ListenConfig{\n  ListenerNetwork:      fiber.NetworkUnix,\n  UnixSocketFileMode:   0o660,\n})","handlingStrategy":"validation","validationCode":"// Pre-flight: ensure the socket path is clearable by this process.\nfunc preflightUnixSocket(path string) error {\n    abs, err := filepath.Abs(path)\n    if err != nil {\n        return err\n    }\n    if info, err := os.Stat(abs); err == nil {\n        if info.IsDir() {\n            return fmt.Errorf(\"socket path %q is a directory\", abs)\n        }\n        if err := os.Remove(abs); err != nil && !os.IsNotExist(err) {\n            return fmt.Errorf(\"cannot remove stale socket %q: %w\", abs, err)\n        }\n    } else if !os.IsNotExist(err) {\n        return err\n    }\n    // parent dir must be writable\n    return os.MkdirAll(filepath.Dir(abs), 0o755)\n}","typeGuard":"null","tryCatchPattern":"err := app.Listen(sock, fiber.ListenConfig{ListenerNetwork: fiber.NetworkUnix})\nif err != nil {\n    var lp *net.OpError\n    if errors.As(err, &lp) && strings.Contains(err.Error(), \"remove unix socket\") {\n        // surface as a deployment/permission issue, not a code bug\n        log.Errorf(\"socket pre-clear failed (%v) — check owner/perms of %s\", err, sock)\n    }\n    return err\n}","preventionTips":["Run the process as the user that owns the socket directory or grant it ownership.","Place unix sockets under a per-app writable dir like /var/lib/<app> or /run/user/<uid>.","Ensure only one instance binds a given socket path; coordinate via a PID/lock file.","Avoid read-only mounts for socket paths; verify with a pre-start write test."],"tags":["unix-socket","filesystem","permissions","startup","network"],"analyzedSha":"9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c","analyzedAt":"2026-08-04T21:44:03.395Z","schemaVersion":2}