kataras/iris · error

cannot chmod %#o for %q: %w

Error message

cannot chmod %#o for %q: %w

What it means

netutil.UNIX wraps net.Listen on a unix socket path, then adjusts the socket file's permission bits with os.Chmod. If the chmod fails (e.g. the file vanished, wrong owner, or unsupported by the filesystem), the listen call is abandoned and this wrapped error is returned, preserving the underlying cause via %w.

Source

Thrown at core/netutil/tcp.go:80

	if err != nil {
		return nil, err
	}
	return tcpKeepAliveListener{ln.(*net.TCPListener), keepAliveDur}, nil
}

// UNIX returns a new unix(file) Listener.
func UNIX(socketFile string, mode os.FileMode) (net.Listener, error) {
	if errOs := os.Remove(socketFile); errOs != nil && !os.IsNotExist(errOs) {
		return nil, fmt.Errorf("%s: %w", socketFile, errOs)
	}

	l, err := net.Listen("unix", socketFile)
	if err != nil {
		return nil, fmt.Errorf("port already in use: %w", err)
	}

	if err = os.Chmod(socketFile, mode); err != nil {
		return nil, fmt.Errorf("cannot chmod %#o for %q: %w", mode, socketFile, err)
	}

	return l, nil
}

// TLS returns a new TLS Listener and an error on failure.
func TLS(addr, certFile, keyFile string) (net.Listener, error) {
	if certFile == "" || keyFile == "" {
		return nil, errors.New("empty certFile or KeyFile")
	}

	cert, err := tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		return nil, err
	}

	return CERT(addr, cert)
}

View on GitHub (pinned to 7bedaf55a0)

Solutions

  1. Check the wrapped cause (%w) — fix the underlying os.Chmod error (ownership, missing file, unsupported filesystem)
  2. Run the process with enough privilege to chmod the socket file, or pre-create the directory with correct owner/permissions
  3. Move the socket file to a local filesystem path such as /tmp or /run where chmod is supported
  4. Ensure no cleanup process deletes the socket file between listen and chmod

Example fix

// before
l, err := netutil.UNIX("/mnt/nfs/app.sock", 0o755)
// after
l, err := netutil.UNIX("/run/myapp/app.sock", 0o755)
Defensive patterns

Strategy: validation

Validate before calling

if fi, err := os.Stat(socketFile); err == nil {
    if fi.Mode()&os.ModeSocket == 0 { return fmt.Errorf("%s exists and is not a socket", socketFile) }
    os.Remove(socketFile)
}
if err := os.MkdirAll(filepath.Dir(socketFile), 0o755); err != nil { return err }

Type guard

func canChmod(path string) bool {
    fi, err := os.Stat(path)
    return err == nil && fi.Mode().Perm() != 0
}

Try / catch

l, err := netutil.UNIX(socketFile, 0o755)
if err != nil {
    var perr *fs.PathError
    if errors.As(err, &perr) { log.Printf("chmod failed: %v", perr.Err) }
    return err
}

Prevention

When it happens

Trigger: Calling netutil.UNIX with a socketFile on a filesystem that does not support chmod semantics (some NFS/network mounts, tmpfs with restrictions), a file system where the process lacks ownership of the freshly created socket, or the socket file being removed between Listen and Chmod.

Common situations: Running the app in a container as non-root while the socket directory has restrictive permissions; deploying to read-only or quirky mounted volumes (Docker bind mounts, NFS); socket path inside a directory cleaned up by another process mid-startup.

Related errors


AI-assisted analysis of kataras/iris@7bedaf55a0 (2026-08-30). Data as JSON: /api/errors/9784223f9252eb9a. Report an issue: GitHub.