{"record":{"id":"3cbfd8419f003905","repo":"apache/hadoop","slug":"storage-policy-are-not-supported-on-symlinks","errorCode":null,"errorMessage":"Storage policy are not supported on symlinks","messagePattern":"Storage policy are not supported on symlinks","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/INodeSymlink.java","lineNumber":144,"sourceCode":"\n  @Override\n  final XAttrFeature getXAttrFeature(int snapshotId) {\n    throw new UnsupportedOperationException(\"XAttrs are not supported on symlinks\");\n  }\n  \n  @Override\n  public void removeXAttrFeature() {\n    throw new UnsupportedOperationException(\"XAttrs are not supported on symlinks\");\n  }\n  \n  @Override\n  public void addXAttrFeature(XAttrFeature f) {\n    throw new UnsupportedOperationException(\"XAttrs are not supported on symlinks\");\n  }\n\n  @Override\n  public byte getStoragePolicyID() {\n    throw new UnsupportedOperationException(\n        \"Storage policy are not supported on symlinks\");\n  }\n\n  @Override\n  public byte getLocalStoragePolicyID() {\n    throw new UnsupportedOperationException(\n        \"Storage policy are not supported on symlinks\");\n  }\n}\n","sourceCodeStart":126,"sourceCodeEnd":154,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/INodeSymlink.java#L126-L154","documentation":"INodeSymlink.getStoragePolicyID unconditionally throws UnsupportedOperationException(\"Storage policy are not supported on symlinks\"). Querying or applying a storage policy resolves the inode's policy id; because block placement applies to the target's blocks, a symlink inode has no policy of its own and this getter refuses rather than returning a bogus id.","triggerScenarios":"`hdfs storagepolicies -getStoragePolicy -path <symlink>`; internal block-placement or mover logic that asks a symlink inode (instead of the resolved file) for its storage policy id.","commonSituations":"Administrators checking policies across user directories that contain symlinks; scripts iterating `hdfs fsck`/storagepolicies output; SPS or mover flows encountering unresolved links.","solutions":["Query the policy of the link's target file/directory (resolve the path first)","Skip symlinks in policy-audit scripts","When writing NN-side code, resolve the INode to a file before consulting getStoragePolicyID"],"exampleFix":"# before\nhdfs storagepolicies -getStoragePolicy -path /data/link-to-file\n# -> UnsupportedOperationException: Storage policy are not supported on symlinks\n\n# after\nTARGET=$(readlink -f <(hdfs dfs -ls /data/link-to-file))  # or resolve manually\nhdfs storagepolicies -getStoragePolicy -path /data/real/file","handlingStrategy":"type-guard","validationCode":"FileStatus st = fs.getFileStatus(p);\nif (st.isSymlink()) {\n  p = st.getSymlink();  // policy lives on the target\n}\n// then: hdfs storagepolicies -getStoragePolicy -path <resolved>","typeGuard":"boolean hasStoragePolicy(FileSystem fs, Path p) throws IOException {\n  return !fs.getFileStatus(p).isSymlink();\n}","tryCatchPattern":"catch (UnsupportedOperationException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"Storage policy\")) {\n    skip(path);  // symlinks carry no policy; query the target instead\n  } else { throw e; }\n}","preventionTips":["Resolve links before policy queries in audit scripts","In NN-internal code, never call getStoragePolicyID on an unresolved INodeSymlink","Keep policy tooling aligned with the fact that placement applies to target blocks"],"tags":["hdfs","storage-policy","symlink","unsupported-operation","namenode"],"backgroundTag":"operation-not-supported-on-file-type","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}