apache/hadoop · error · IOException
Destination '{destFile}' exists but is read-only
Error message
Destination '{destFile}' exists but is read-only What it means
Guard clause of Storage.nativeCopyFileUnbuffered: destFile exists and FileUtil.canWrite(destFile) is false, so the method refuses to proceed. The check intentionally uses FileUtil.canWrite (which opens the file for append) rather than File.canWrite, so it fails for ownership mismatches even when mode bits look writable.
Source
Thrown at hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/common/Storage.java:1351
throw new FileNotFoundException("Source '" + srcFile + "' does not exist");
}
if (srcFile.isDirectory()) {
throw new IOException("Source '" + srcFile + "' exists but is a directory");
}
if (srcFile.getCanonicalPath().equals(destFile.getCanonicalPath())) {
throw new IOException("Source '" + srcFile + "' and destination '" +
destFile + "' are the same");
}
File parentFile = destFile.getParentFile();
if (parentFile != null) {
if (!parentFile.mkdirs() && !parentFile.isDirectory()) {
throw new IOException("Destination '" + parentFile
+ "' directory cannot be created");
}
}
if (destFile.exists()) {
if (FileUtil.canWrite(destFile) == false) {
throw new IOException("Destination '" + destFile
+ "' exists but is read-only");
} else {
if (destFile.delete() == false) {
throw new IOException("Destination '" + destFile
+ "' exists but cannot be deleted");
}
}
}
try {
NativeIO.copyFileUnbuffered(srcFile, destFile);
} catch (NativeIOException e) {
throw new IOException("Failed to copy " + srcFile.getCanonicalPath()
+ " to " + destFile.getCanonicalPath()
+ " due to failure in NativeIO#copyFileUnbuffered(). "
+ e.toString());
}
if (srcFile.length() != destFile.length()) {
throw new IOException("Failed to copy full contents from '" + srcFileView on GitHub (pinned to 2add963021)
Solutions
- chown the file to the daemon user or grant write: chown hdfs:hdfs <dest> or chmod u+w <dest>
- Remove the file if a fresh copy is intended (the method would delete and rewrite it once writable)
- Remount the filesystem read-write if applicable and clear immutable attributes (chattr -i)
Example fix
# before: dest owned by root, mode 644, daemon runs as hdfs # after chown hdfs:hdfs /data/dest/fsimage && chmod u+w /data/dest/fsimage
Defensive patterns
Strategy: validation
Validate before calling
if (destFile.exists() && !FileUtil.canWrite(destFile)) {
throw new IOException("destination not writable by " + UserGroupInformation.getLoginUser()
+ ": " + destFile);
} Prevention
- Use FileUtil.canWrite (it actually opens the file), not File.canWrite, when pre-checking
- Standardize ownership of storage files on the daemon user
- Avoid read-only mounts for directories that receive copies
When it happens
Trigger: The destination is owned by another user with no write grant for the daemon user; mode is read-only (e.g. 444); the file has the immutable attribute; the filesystem is mounted read-only; ACLs deny the daemon user.
Common situations: Files copied in as root and left root-owned; images/backups restored without fixing ownership; hardening scripts that chmod read-only; RO mounts for recovery.
Related errors
- Destination '{parentFile}' directory cannot be created
- Permission denied: user=%s, path="%s":%s:%s:%s%s
- {} doesn't support modifyAclEntries
- {} doesn't support removeAclEntries
- {} doesn't support removeAcl
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/b2e10bd49f0e35fa.
Report an issue: GitHub.