apache/hadoop · error · AccessControlException

The xattr 'security.hdfs.unreadable.by.superuser' can not be

Error message

The xattr 'security.hdfs.unreadable.by.superuser' can not be deleted.

What it means

security.hdfs.unreadable.by.superuser is an internal protection flag: once set by a privileged client it hides the file's content even from the HDFS superuser. unprotectedRemoveXAttrs rejects any removal attempt with AccessControlException; there is deliberately no API to delete it, because that would defeat its security purpose. The adjacent guard likewise forbids deleting the encryption-zone key id xattr.

Source

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

    throws AccessControlException {
    if (existingXAttrs == null || existingXAttrs.isEmpty() ||
        toFilter == null || toFilter.isEmpty()) {
      return existingXAttrs;
    }

    // Populate a new list with XAttrs that pass the filter
    List<XAttr> newXAttrs =
        Lists.newArrayListWithCapacity(existingXAttrs.size());
    for (XAttr a : existingXAttrs) {
      boolean add = true;
      for (ListIterator<XAttr> it = toFilter.listIterator(); it.hasNext()
          ;) {
        XAttr filter = it.next();
        Preconditions.checkArgument(
            !KEYID_XATTR.equalsIgnoreValue(filter),
            "The encryption zone xattr should never be deleted.");
        if (UNREADABLE_BY_SUPERUSER_XATTR.equalsIgnoreValue(filter)) {
          throw new AccessControlException("The xattr '" +
              SECURITY_XATTR_UNREADABLE_BY_SUPERUSER + "' can not be deleted.");
        }
        if (a.equalsIgnoreValue(filter)) {
          add = false;
          it.remove();
          filtered.add(filter);
          break;
        }
      }
      if (add) {
        newXAttrs.add(a);
      }
    }

    return newXAttrs;
  }

  public static INode unprotectedSetXAttrs(

View on GitHub (pinned to 2add963021)

Solutions

  1. Skip protected attributes in removal loops: never touch security.hdfs.unreadable.by.superuser, and filter raw./system. namespaces
  2. To actually drop the protection, copy the file content to a new file (the xattr does not carry over) and swap names
  3. Fix bulk tooling to filter xattrs by namespace before calling removeXAttr

Example fix

// before: strip everything
for (String name : fs.listXAttrs(path)) {
  fs.removeXAttr(path, name); // AccessControlException on protected xattr
}

// after: skip protected/internal namespaces
for (String name : fs.listXAttrs(path)) {
  if (!name.startsWith("security.") && !name.startsWith("system.")
      && !name.startsWith("raw.")) {
    fs.removeXAttr(path, name);
  }
}
Defensive patterns

Strategy: validation

Validate before calling

for (String name : fs.listXAttrs(path)) {
  if (!isProtectedXattr(name)) {
    fs.removeXAttr(path, name);
  }
}

Type guard

static boolean isProtectedXattr(String name) {
  return "security.hdfs.unreadable.by.superuser".equals(name)
      || name.startsWith("system.")
      || name.startsWith("raw.");
}

Try / catch

try {
  fs.removeXAttr(path, name);
} catch (AccessControlException e) {
  // protected attribute: skip it in bulk-removal loops instead of failing
}

Prevention

When it happens

Trigger: removeXAttr (or bulk delete-all-xattrs logic) that includes security.hdfs.unreadable.by.superuser in the list; the same method also rejects the raw encryption-zone keyid xattr via Preconditions.

Common situations: Generic xattr dump/restore, anonymization, or cleanup tools that enumerate and strip every attribute; migration scripts that try to normalize xattrs across trees.

Related errors


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