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 '" + srcFile

View on GitHub (pinned to 2add963021)

Solutions

  1. chown the file to the daemon user or grant write: chown hdfs:hdfs <dest> or chmod u+w <dest>
  2. Remove the file if a fresh copy is intended (the method would delete and rewrite it once writable)
  3. 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

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


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/b2e10bd49f0e35fa. Report an issue: GitHub.