apache/cassandra · error · RuntimeException

Insufficient permissions on directory

Error message

Insufficient permissions on directory <path>

What it means

Before listing sstables for import, SSTableImporter calls Directories.verifyFullPermissions on each source directory. If the permissions are insufficient (not readable/writable/executable by the Cassandra user) it throws a RuntimeException. The importer must be able to read the sstables and interact with transaction log files, so weak permissions are rejected up front.

Solutions

  1. chown the directory and its contents to the user running Cassandra (usually cassandra:cassandra): `chown -R cassandra:cassandra <path>`
  2. Grant full permissions for the Cassandra user: `chmod -R u+rwx <path>`
  3. Verify with `sudo -u cassandra ls -la <path>` that the service user can read and traverse the directory
  4. Check SELinux/AppArmor denials in audit logs if permissions look correct

Example fix

// before (shell)
-rw------- root root /staging/sstables-00001.db
// after
chown -R cassandra:cassandra /staging && chmod -R u+rwX /staging
Defensive patterns

Strategy: validation

Validate before calling

File dir = new File(path);
if (!dir.canRead() || !dir.canWrite() || !dir.canExecute())
    throw new IllegalStateException("Insufficient permissions for cassandra user on: " + path);

Type guard

boolean isFullyAccessible(String p) { File d = new File(p); return d.isDirectory() && d.canRead() && d.canWrite() && d.canExecute(); }

Try / catch

try { importer.importNewSSTables(...); } catch (RuntimeException e) { if (e.getMessage() != null && e.getMessage().startsWith("Insufficient permissions")) { /* chown/chmod and retry */ } else throw e; }

Prevention

When it happens

Trigger: Importing sstables from a directory owned by root or another user, or with restrictive mode bits (e.g. 0700 owned by another account), when running as the cassandra service user.

Common situations: Files copied into place with sudo/scp as root; backup restores where permissions were not preserved; sstables streamed from another cluster with different uid; SELinux/AppArmor restrictions.

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/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/7618c8c3bcdfd251. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/db/SSTableImporter.java:329

     *
     * If srcPaths is empty, we create a lister that lists sstables in the data directories (deprecated use)
     */
    private List<Pair<Directories.SSTableLister, String>> getSSTableListers(Set<String> srcPaths)
    {
        List<Pair<Directories.SSTableLister, String>> listers = new ArrayList<>();

        if (!srcPaths.isEmpty())
        {
            for (String path : srcPaths)
            {
                File dir = new File(path);
                if (!dir.exists())
                {
                    throw new RuntimeException(String.format("Directory %s does not exist", path));
                }
                if (!Directories.verifyFullPermissions(dir, path))
                {
                    throw new RuntimeException("Insufficient permissions on directory " + path);
                }
                listers.add(Pair.create(cfs.getDirectories().sstableLister(dir, Directories.OnTxnErr.IGNORE).skipTemporary(true), path));
            }
        }
        else
        {
            listers.add(Pair.create(cfs.getDirectories().sstableLister(Directories.OnTxnErr.IGNORE).skipTemporary(true), null));
        }

        return listers;
    }

    private static class MovedSSTable
    {
        private final Descriptor newDescriptor;
        private final Descriptor oldDescriptor;
        private final Set<Component> components;

View on GitHub (pinned to 88fd0f6a0e)