apache/hadoop · error · IOException

Can only set 'security.hdfs.unreadable.by.superuser' on a fi

Error message

Can only set 'security.hdfs.unreadable.by.superuser' on a file.

What it means

The unreadable-by-superuser marker is a per-file security property: it hides file data from the superuser, a notion defined only for file content. setINodeXAttrs throws IOException when the attribute is applied to a non-file inode such as a directory.

Source

Thrown at hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSDirXAttrOp.java:306

            PBHelperClient.convert(ezProto.getSuite()),
            PBHelperClient.convert(ezProto.getCryptoProtocolVersion()),
            ezProto.getKeyName());

        if (ezProto.hasReencryptionProto()) {
          ReencryptionInfoProto reProto = ezProto.getReencryptionProto();
          fsd.ezManager.getReencryptionStatus()
              .updateZoneStatus(inode.getId(), iip.getPath(), reProto);
        }
      }

      // Add inode id to movement queue if xattrs contain satisfy xattr.
      if (XATTR_SATISFY_STORAGE_POLICY.equals(xaName)) {
        FSDirSatisfyStoragePolicyOp.unprotectedSatisfyStoragePolicy(inode, fsd);
        continue;
      }

      if (!isFile && SECURITY_XATTR_UNREADABLE_BY_SUPERUSER.equals(xaName)) {
        throw new IOException("Can only set '" +
            SECURITY_XATTR_UNREADABLE_BY_SUPERUSER + "' on a file.");
      }

      if (xaName.equals(XATTR_SNAPSHOT_DELETED) && !(inode.isDirectory() &&
          inode.getParent().isSnapshottable())) {
        throw new IOException("Can only set '" +
            XATTR_SNAPSHOT_DELETED + "' on a snapshot root.");
      }
    }

    XAttrStorage.updateINodeXAttrs(inode, newXAttrs, iip.getLatestSnapshotId());
    return inode;
  }

  static List<XAttr> setINodeXAttrs(
      FSDirectory fsd, final List<XAttr> existingXAttrs,
      final List<XAttr> toSet, final EnumSet<XAttrSetFlag> flag)
      throws IOException {

View on GitHub (pinned to 2add963021)

Solutions

  1. Apply only to files: guard with fs.getFileStatus(path).isFile()
  2. For directory trees, walk contained files (listFiles with recursion) and tag each file, skipping directories
  3. If a bulk walk cannot pre-filter, catch and ignore this IOException for directory entries

Example fix

// before: blanket apply across a tree
fs.setXAttr(dirPath, "security.hdfs.unreadable.by.superuser", new byte[0]);

// after: files only
RemoteIterator<LocatedFileStatus> it = fs.listFiles(root, true);
while (it.hasNext()) {
  fs.setXAttr(it.next().getPath(),
      "security.hdfs.unreadable.by.superuser", new byte[0]);
}
Defensive patterns

Strategy: validation

Validate before calling

if (fs.getFileStatus(path).isFile()) {
  fs.setXAttr(path, "security.hdfs.unreadable.by.superuser", new byte[0]);
} // directories skipped by design

Type guard

static boolean isRegularFile(FileSystem fs, Path p) throws IOException {
  return fs.exists(p) && fs.getFileStatus(p).isFile();
}

Try / catch

try {
  fs.setXAttr(path, "security.hdfs.unreadable.by.superuser", new byte[0]);
} catch (IOException e) {
  if (!fs.getFileStatus(path).isFile()) {
    // directory entry in a recursive walk: ignore
  } else { throw e; }
}

Prevention

When it happens

Trigger: setXAttr(path, "security.hdfs.unreadable.by.superuser", value) where path resolves to a directory, typically during a recursive walk that applies the marker to a whole tree including its directories.

Common situations: Recursive privacy tagging over directory trees; tools built for file paths pointed at mount roots; backup scripts reapplying captured xattrs verbatim.

Related errors


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