apache/cassandra · error · RuntimeException
Unable to create directory
Error message
Unable to create directory ${logDir} What it means
After validating the log directory location, maybeCreateProfilesLogDir attempts to create it (createDirectoriesIfNotExists). If that filesystem operation fails for any reason (permissions, read-only volume, path is a file), the original cause is discarded and a RuntimeException with the log dir path is thrown, so callers can see which directory could not be created.
Solutions
- Create the directory manually as the user running Cassandra and chown it appropriately (mkdir -p && chown cassandra)
- Fix the configured log dir path (typo, wrong mount) to a writable location
- Check filesystem mount flags/permissions (read-only, SELinux context) and remount or relabel
- Inspect the original cause in Cassandra's debug logs if present; the rethrown message omits it
Example fix
// before async_profiler_dir: /proc/cassandra-prof // after sudo mkdir -p /var/log/cassandra/async-profiler && sudo chown cassandra:cassandra /var/log/cassandra/async-profiler
Defensive patterns
Strategy: try-catch
Validate before calling
Path p = Path.of(logDir); if (!Files.isDirectory(p)) Files.createDirectories(p); // fail early with a clear cause if (!Files.isWritable(p)) throw new AccessDeniedException(p.toString());
Try / catch
try { svc.apply(cmd, file); } catch (RuntimeException e) { if (e.getMessage().startsWith("Unable to create directory")) { Files.createDirectories(Path.of(logDir)); svc.apply(cmd, file); } else throw e; } Prevention
- Pre-create the profiler log dir as the cassandra user with correct ownership
- Verify the target mount is writable (not read-only, not full)
- Check SELinux/AppArmor policies for the chosen path
- Log the underlying cause — the rethrown RuntimeException hides it
When it happens
Trigger: Profiling MBean calls (instance/apply/list/fetch/purge) when the configured log dir cannot be created: parent dirs missing and uncreatable, OS permission denied, read-only filesystem, or a regular file already exists at that path.
Common situations: Non-root Cassandra user lacking write access to the configured path; Docker/Kubernetes volumes mounted read-only; SELinux/AppArmor denials; disk full or typo in the directory path.
Understand the failure class
Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.
Related errors
- Could not list files in
- Dictionary file is not readable.
- Directory doesn't exist
- ERR_WRONG_DISK_STATE
- Failed to delete
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/13c13d51b417571a.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/service/AsyncProfilerService.java:448
(DatabaseDescriptor.getCDCLogLocation() != null && dir.startsWith(DatabaseDescriptor.getCDCLogLocation())) ||
(DatabaseDescriptor.getSavedCachesLocation() != null && dir.startsWith(DatabaseDescriptor.getSavedCachesLocation())))
{
throw new RuntimeException("You can not store Async-Profiler results into system Cassandra directory.");
}
for (String location : StorageService.instance.getAllDataFileLocations())
{
if (dir.startsWith(location))
throw new RuntimeException("You can not store Async-Profiler results into a data directory of Cassandra.");
}
try
{
new File(logDir).createDirectoriesIfNotExists();
}
catch (Throwable t)
{
throw new RuntimeException("Unable to create directory " + logDir);
}
}
private void validateStartParameters(Map<String, String> parameters)
{
if (!ASYNC_PROFILER_START_PARAMS.equals(parameters.keySet()))
{
throw new IllegalArgumentException("Wrong parameters passed to start async profiler method. Passed parameters" +
" should be: " + ASYNC_PROFILER_START_PARAMS);
}
}
private void validateStopParameters(Map<String, String> parameters)
{
if (!ASYNC_PROFILER_STOP_PARAMS.containsAll(parameters.keySet()))
{
throw new IllegalArgumentException("Wrong parameters passed to stop async profiler method. Passed parameters" +
" should be: " + ASYNC_PROFILER_STOP_PARAMS);View on GitHub (pinned to 88fd0f6a0e)