apache/druid · error · IllegalStateException
Path [%s] is not writable, check permissions
Error message
Path [%s] is not writable, check permissions
What it means
FileUtils.createTempDirInLocation throws this ISE when the JVM cannot create a temporary directory because the OS reported the parent path is not writable. It maps AccessDeniedException or a 'Read-only file system' FileSystemException from the underlying createDirectory call to this clearer message. It indicates a filesystem permission or mount-state problem, not a bug in caller code.
Source
Thrown at processing/src/main/java/org/apache/druid/java/util/common/FileUtils.java:490
}
@SuppressForbidden(reason = "Files#createTempDirectory")
public static File createTempDirInLocation(final Path parentDirectory, @Nullable final String prefix)
{
try {
final Path tmpPath = Files.createTempDirectory(
parentDirectory,
prefix == null || prefix.isEmpty() ? "druid" : prefix
);
return tmpPath.toFile();
}
catch (IOException e) {
// Some inspection to improve error messages.
if (e instanceof NoSuchFileException && !parentDirectory.toFile().exists()) {
throw new ISE("Path [%s] does not exist", parentDirectory);
} else if ((e instanceof FileSystemException && e.getMessage().contains("Read-only file system"))
|| (e instanceof AccessDeniedException)) {
throw new ISE("Path [%s] is not writable, check permissions", parentDirectory);
} else {
// Well, maybe it was something else.
throw new ISE(e, "Failed to create temporary directory in path [%s]", parentDirectory);
}
}
}
/**
* Create "directory" and all intermediate directories as needed. If the directory is successfully created, or already
* exists, returns quietly. Otherwise, throws an IOException.
*
* Simpler to use than {@link File#mkdirs()}, and more reliable since it is safe from races where two threads try
* to create the same directory at the same time.
*
* The name is inspired by UNIX {@code mkdir -p}, which has the same behavior.
*/
@SuppressForbidden(reason = "File#mkdirs")
public static void mkdirp(final File directory) throws IOExceptionView on GitHub (pinned to 9b90983fd2)
Solutions
- Check and fix permissions on the parent directory: chown/chmod so the process user has write access
- Point the temp-dir configuration at a writable location (e.g. a writable volume or /tmp)
- If the filesystem was remounted read-only, remount it read-write or fix the underlying disk issue
- In containers, mount a writable emptyDir/PV for temp directories and avoid readOnlyRootFilesystem without mounts
- Verify with: sudo -u <druid-user> touch <path>/writetest
Example fix
// before
FileUtils.createTempDir(new File("/opt/druid/tmp")); // /opt is read-only
// after
FileUtils.createTempDir(new File("/var/tmp/druid")); // writable volume Defensive patterns
Strategy: try-catch
Validate before calling
File dir = new File(path);
if (!dir.isDirectory()) throw new IllegalStateException("Not a directory: " + path);
File probe = new File(dir, ".write-probe");
try { if (!probe.createNewFile()) throw new IllegalStateException("Not writable"); }
finally { probe.delete(); } Type guard
static boolean isWritableDir(File dir) {
return dir != null && dir.isDirectory() && dir.canWrite();
} Try / catch
try {
File tmp = FileUtils.createTempDir(parent);
} catch (ISE e) {
if (e.getMessage() != null && e.getMessage().contains("not writable")) {
// fix permissions or switch to fallback dir
tmp = FileUtils.createTempDir(new File(System.getProperty("java.io.tmpdir")));
} else throw e;
} Prevention
- Run the process as a user with write access to configured temp paths
- Mount a writable volume for temp dirs in containers with read-only root filesystems
- Add a startup health check that probes write access to all configured directories
- Monitor for filesystems remounting read-only (dmesg / mount state alerts)
When it happens
Trigger: Calling FileUtils.createTempDir (which delegates to createTempDirInLocation) with a parent directory the process cannot write to, on a read-only mounted filesystem, or where the directory's permission bits deny write access to the running user.
Common situations: Configuring druid.server.tempDir or intermediate persist dirs on a read-only container filesystem; running Druid as a non-root user without write access to java.io.tmpdir; disk remounted read-only after hardware errors; Kubernetes readOnlyRootFilesystem without an emptyDir mount.
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
- Cannot create tempDir [%s] for google storage connector
- Cannot list directory [%s]
- Could not create temp distribution directory.
- Could not close channel for level [%d] and rank [%d]
- Unable to close channel for name :
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/6093c5183579163e.
Report an issue: GitHub.