{"record":{"id":"ff603908537b15a6","repo":"apache/pulsar","slug":"dir-directory-does-not-have-read-privilege","errorCode":null,"errorMessage":"${dir} directory does not have read privilege","messagePattern":"(.+?) directory does not have read privilege","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"pulsar-common/src/main/java/org/apache/pulsar/common/nar/FileUtils.java","lineNumber":103,"sourceCode":"                throw new IOException(dir.getAbsolutePath() + \" could not be created\");\n            }\n        }\n        if (!(dir.canRead() && dir.canWrite())) {\n            throw new IOException(dir.getAbsolutePath() + \" directory does not have read/write privilege\");\n        }\n    }\n\n    public static void ensureDirectoryExistAndCanRead(final File dir) throws IOException {\n        if (dir.exists() && !dir.isDirectory()) {\n            throw new IOException(dir.getAbsolutePath() + \" is not a directory\");\n        } else if (!dir.exists()) {\n            final boolean made = dir.mkdirs();\n            if (!made) {\n                throw new IOException(dir.getAbsolutePath() + \" could not be created\");\n            }\n        }\n        if (!dir.canRead()) {\n            throw new IOException(dir.getAbsolutePath() + \" directory does not have read privilege\");\n        }\n    }\n\n    private static boolean deleteFile(final File file, final int attempts) {\n        if (file == null) {\n            return false;\n        }\n        boolean isGone = false;\n        try {\n            if (file.exists()) {\n                final int effectiveAttempts = Math.max(1, attempts);\n                for (int i = 0; i < effectiveAttempts && !isGone; i++) {\n                    isGone = file.delete() || !file.exists();\n                    if (!isGone && (effectiveAttempts - i) > 1) {\n                        FileUtils.sleepQuietly(MILLIS_BETWEEN_ATTEMPTS);\n                    }\n                }\n                if (!isGone) {","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-common/src/main/java/org/apache/pulsar/common/nar/FileUtils.java#L85-L121","documentation":"ensureDirectoryExistAndCanRead ends by checking File.canRead(); if false it throws IOException '<abs path> directory does not have read privilege'. The directory exists, but the process user lacks read permission, so its contents cannot be listed.","triggerScenarios":"Directory mode denies read (e.g. 300 = write/execute only) or ACL/OS policy blocks reading for the process user.","commonSituations":"Directories provisioned by automation with restrictive modes, root-owned dirs read by non-root services, hardened SELinux policies, or NFS exports without read for the mapped uid.","solutions":["chmod u+r (or o+r as appropriate) on the directory.","chown the directory to the service user.","Check getenforce/audit logs for SELinux denials and fix the policy or context.","Verify NFS/AD uid mapping grants read access."],"exampleFix":"// shell fix\n// chmod a+rx /var/lib/pulsar/nar  # or chown pulsar:pulsar","handlingStrategy":"validation","validationCode":"if (dir.exists() && !dir.canRead()) {\n    throw new IllegalStateException(\"No read permission on \" + dir);\n}","typeGuard":null,"tryCatchPattern":"try {\n    FileUtils.ensureDirectoryExistAndCanRead(dir);\n} catch (IOException e) {\n    if (e.getMessage().contains(\"read privilege\")) {\n        log.error(\"Grant read: chmod a+rx {} or chown to service user\", dir);\n    }\n    throw e;\n}","preventionTips":["Include canRead() checks in startup readiness probes","Keep directory modes at least 755 (or owner r-x) for service-readable dirs","Re-verify permissions after restores, migrations, or NFS re-exports"],"tags":["filesystem","permissions","io"],"backgroundTag":"permission-denied","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}