{"record":{"id":"dbb95c7d585f13b3","repo":"apache/hadoop","slug":"can-only-set-security-hdfs-unreadable-by-superuse","errorCode":null,"errorMessage":"Can only set 'security.hdfs.unreadable.by.superuser' on a file.","messagePattern":"Can only set 'security\\.hdfs\\.unreadable\\.by\\.superuser' on a file\\.","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSDirXAttrOp.java","lineNumber":306,"sourceCode":"            PBHelperClient.convert(ezProto.getSuite()),\n            PBHelperClient.convert(ezProto.getCryptoProtocolVersion()),\n            ezProto.getKeyName());\n\n        if (ezProto.hasReencryptionProto()) {\n          ReencryptionInfoProto reProto = ezProto.getReencryptionProto();\n          fsd.ezManager.getReencryptionStatus()\n              .updateZoneStatus(inode.getId(), iip.getPath(), reProto);\n        }\n      }\n\n      // Add inode id to movement queue if xattrs contain satisfy xattr.\n      if (XATTR_SATISFY_STORAGE_POLICY.equals(xaName)) {\n        FSDirSatisfyStoragePolicyOp.unprotectedSatisfyStoragePolicy(inode, fsd);\n        continue;\n      }\n\n      if (!isFile && SECURITY_XATTR_UNREADABLE_BY_SUPERUSER.equals(xaName)) {\n        throw new IOException(\"Can only set '\" +\n            SECURITY_XATTR_UNREADABLE_BY_SUPERUSER + \"' on a file.\");\n      }\n\n      if (xaName.equals(XATTR_SNAPSHOT_DELETED) && !(inode.isDirectory() &&\n          inode.getParent().isSnapshottable())) {\n        throw new IOException(\"Can only set '\" +\n            XATTR_SNAPSHOT_DELETED + \"' on a snapshot root.\");\n      }\n    }\n\n    XAttrStorage.updateINodeXAttrs(inode, newXAttrs, iip.getLatestSnapshotId());\n    return inode;\n  }\n\n  static List<XAttr> setINodeXAttrs(\n      FSDirectory fsd, final List<XAttr> existingXAttrs,\n      final List<XAttr> toSet, final EnumSet<XAttrSetFlag> flag)\n      throws IOException {","sourceCodeStart":288,"sourceCodeEnd":324,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSDirXAttrOp.java#L288-L324","documentation":"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.","triggerScenarios":"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.","commonSituations":"Recursive privacy tagging over directory trees; tools built for file paths pointed at mount roots; backup scripts reapplying captured xattrs verbatim.","solutions":["Apply only to files: guard with fs.getFileStatus(path).isFile()","For directory trees, walk contained files (listFiles with recursion) and tag each file, skipping directories","If a bulk walk cannot pre-filter, catch and ignore this IOException for directory entries"],"exampleFix":"// before: blanket apply across a tree\nfs.setXAttr(dirPath, \"security.hdfs.unreadable.by.superuser\", new byte[0]);\n\n// after: files only\nRemoteIterator<LocatedFileStatus> it = fs.listFiles(root, true);\nwhile (it.hasNext()) {\n  fs.setXAttr(it.next().getPath(),\n      \"security.hdfs.unreadable.by.superuser\", new byte[0]);\n}","handlingStrategy":"validation","validationCode":"if (fs.getFileStatus(path).isFile()) {\n  fs.setXAttr(path, \"security.hdfs.unreadable.by.superuser\", new byte[0]);\n} // directories skipped by design","typeGuard":"static boolean isRegularFile(FileSystem fs, Path p) throws IOException {\n  return fs.exists(p) && fs.getFileStatus(p).isFile();\n}","tryCatchPattern":"try {\n  fs.setXAttr(path, \"security.hdfs.unreadable.by.superuser\", new byte[0]);\n} catch (IOException e) {\n  if (!fs.getFileStatus(path).isFile()) {\n    // directory entry in a recursive walk: ignore\n  } else { throw e; }\n}","preventionTips":["Apply per-file security markers only after an isFile() check","In recursive walks, skip directories when tagging","Test privacy-tagging tools against mixed file/dir trees"],"tags":["hdfs","xattr","security","type-mismatch","files-vs-dirs"],"backgroundTag":"attribute-type-mismatch","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}