valyala/fasthttp · error
cannot chmod %#o for %q: %w
Error message
cannot chmod %#o for %q: %w
What it means
Returned by Server.ListenAndServeUNIX when os.Chmod on the newly created unix socket file fails while applying the requested file mode. The listener is closed first to avoid leaking the socket fd. Binding succeeded but the mode change on the socket inode did not.
Source
Thrown at server.go:1796
// ListenAndServeUNIX serves HTTP requests from the given UNIX addr.
//
// The function deletes existing file at addr before starting serving.
//
// The server sets the given file mode for the UNIX addr.
func (s *Server) ListenAndServeUNIX(addr string, mode os.FileMode) error {
if err := os.Remove(addr); err != nil && !os.IsNotExist(err) {
return fmt.Errorf("unexpected error when trying to remove unix socket file %q: %w", addr, err)
}
ln, err := net.Listen("unix", addr)
if err != nil {
return err
}
if err = os.Chmod(addr, mode); err != nil {
// Close the listener so the unix socket file descriptor is not
// leaked when chmod fails before Serve takes ownership of it.
_ = ln.Close()
return fmt.Errorf("cannot chmod %#o for %q: %w", mode, addr, err)
}
return s.Serve(ln)
}
// ListenAndServeTLS serves HTTPS requests from the given TCP4 addr.
//
// certFile and keyFile are paths to TLS certificate and key files.
//
// Pass custom listener to Serve if you need listening on non-TCP4 media
// such as IPv6.
//
// If the certFile or keyFile has not been provided to the server structure,
// the function will use the previously added TLS configuration.
//
// Accepted connections are configured to enable TCP keep-alives.
func (s *Server) ListenAndServeTLS(addr, certFile, keyFile string) error {
ln, err := net.Listen("tcp4", addr)
if err != nil {View on GitHub (pinned to c96f600972)
Solutions
- Ensure the socket path is on a local filesystem that supports chmod (tmpfs/local disk, not NFS).
- Use an app-owned directory so no other process can replace the socket file between listen and chmod.
- Check the wrapped error for the exact errno and fix the underlying permission/capability issue.
- As a workaround, restrict access via directory permissions instead of the socket mode.
Example fix
// before
app.ListenAndServeUNIX("/mnt/nfs/app.sock", 0o600) // chmod unsupported on NFS
// after
app.ListenAndServeUNIX("/run/app/app.sock", 0o600) Defensive patterns
Strategy: try-catch
Validate before calling
// Verify the target filesystem supports chmod before binding
dir := filepath.Dir(sockPath)
probe := filepath.Join(dir, ".permtest")
if err := os.WriteFile(probe, nil, 0o600); err == nil {
err = os.Chmod(probe, 0o644)
os.Remove(probe)
if err != nil { log.Fatalf("filesystem %s does not support chmod", dir) }
} Try / catch
err := app.ListenAndServeUNIX(sockPath, 0o600)
if err != nil && strings.Contains(err.Error(), "cannot chmod") {
_ = sockPath // move socket to a local fs and ensure no race on the path
log.Fatalf("chmod on socket failed: %v", err)
} Prevention
- Bind unix sockets only on local filesystems (tmpfs/disk), not NFS.
- Use a dedicated directory no other process writes to.
- Run a single instance per socket path to avoid races.
- Prefer directory-level permissions over relying on socket chmod.
When it happens
Trigger: os.Chmod returns an error on the freshly bound socket path — most commonly because the process does not own the socket file (e.g. path existed and was re-created by another user via race) or filesystem restrictions (some mounts, e.g. certain network filesystems, disallow chmod).
Common situations: Socket directory on a filesystem that doesn't support chmod; another process raced and replaced the socket file between listen and chmod; running with restricted capabilities where fchmod on the inode is denied.
Related errors
- unexpected error when trying to remove unix socket file %q:
- must implement readat
- directory index required
- no 'create file' permissions
- seek is not implemented
AI-assisted analysis of valyala/fasthttp@c96f600972 (2026-08-31).
Data as JSON: /api/errors/2827d032815baf2e.
Report an issue: GitHub.