apache/pulsar · error · IOException

${dir} directory does not have read/write privilege

Error message

${dir} directory does not have read/write privilege

What it means

ensureDirectoryExistAndCanReadAndWrite finishes by verifying File.canRead() && canWrite(); if either is false it throws IOException '<abs path> directory does not have read/write privilege'. This happens when the directory exists but the process user lacks read or write permission bits (or ACL/OS policy blocks access).

Source

Thrown at pulsar-common/src/main/java/org/apache/pulsar/common/nar/FileUtils.java:89

            }

            return digest.digest();
        } catch (NoSuchAlgorithmException nsae) {
            throw new IllegalArgumentException(nsae);
        }
    }

    public static void ensureDirectoryExistAndCanReadAndWrite(final File dir) throws IOException {
        if (dir.exists() && !dir.isDirectory()) {
            throw new IOException(dir.getAbsolutePath() + " is not a directory");
        } else if (!dir.exists()) {
            final boolean made = dir.mkdirs();
            if (!made) {
                throw new IOException(dir.getAbsolutePath() + " could not be created");
            }
        }
        if (!(dir.canRead() && dir.canWrite())) {
            throw new IOException(dir.getAbsolutePath() + " directory does not have read/write privilege");
        }
    }

    public static void ensureDirectoryExistAndCanRead(final File dir) throws IOException {
        if (dir.exists() && !dir.isDirectory()) {
            throw new IOException(dir.getAbsolutePath() + " is not a directory");
        } else if (!dir.exists()) {
            final boolean made = dir.mkdirs();
            if (!made) {
                throw new IOException(dir.getAbsolutePath() + " could not be created");
            }
        }
        if (!dir.canRead()) {
            throw new IOException(dir.getAbsolutePath() + " directory does not have read privilege");
        }
    }

    private static boolean deleteFile(final File file, final int attempts) {

View on GitHub (pinned to 820761864e)

Solutions

  1. chown -R the directory to the user running the process, or chmod u+rwx on it.
  2. Restart the service under the user that owns the directory.
  3. Check SELinux/AppArmor audit logs and adjust policy or file context.
  4. For NFS, fix root-squash / export permissions.

Example fix

// shell fix
// chown -R pulsar:pulsar /var/lib/pulsar/nar && chmod -R u+rwX /var/lib/pulsar/nar
Defensive patterns

Strategy: try-catch

Validate before calling

if (dir.exists() && !(dir.canRead() && dir.canWrite())) {
    throw new IllegalStateException("Insufficient permissions on " + dir
        + ": read=" + dir.canRead() + " write=" + dir.canWrite());
}

Try / catch

try {
    FileUtils.ensureDirectoryExistAndCanReadAndWrite(dir);
} catch (IOException e) {
    if (e.getMessage().contains("read/write privilege")) {
        log.error("Fix ownership: chown -R {}:{} {}", serviceUser, serviceGroup, dir);
    }
    throw e;
}

Prevention

When it happens

Trigger: The directory (existing or freshly created by a different user) has mode bits denying read or write to the process user, e.g. a root-created directory with mode 700 encountered by a non-root broker process.

Common situations: A previous run as root created the NAR/cache directory; shared NFS mounts exporting root-squashed permissions; hardening policies (SELinux) denying writes; umask producing restrictive modes.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/52cc31d3f9539e4d. Report an issue: GitHub.