{"record":{"id":"7f81799896c66409","repo":"apache/hadoop","slug":"permission-denied-rename-to-reason","errorCode":null,"errorMessage":"Permission denied rename {}({}) to {}({}) Reason={}","messagePattern":"Permission denied rename (.+?)\\((.+?)\\) to (.+?)\\((.+?)\\) Reason=(.+?)","errorType":"exception","errorClass":"AccessControlException","httpStatus":null,"severity":"error","filePath":"hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/java/org/apache/hadoop/hdfs/server/federation/router/RouterFederationRename.java","lineNumber":166,"sourceCode":"      throws IOException {\n    try {\n      if (UserGroupInformation.isSecurityEnabled()) {\n        // In security mode, check permission as remote user proxy by router\n        // user.\n        String remoteUserName = NameNode.getRemoteUser().getShortUserName();\n        UserGroupInformation proxyUser = UserGroupInformation\n            .createProxyUser(remoteUserName,\n                UserGroupInformation.getLoginUser());\n        proxyUser.doAs((PrivilegedExceptionAction<Object>) () -> {\n          checkRenamePermission(src, dst);\n          return null;\n        });\n      } else {\n        // In simple mode, check permission as remote user directly.\n        checkRenamePermission(src, dst);\n      }\n    } catch (AccessControlException e) {\n      throw new AccessControlException(\n          \"Permission denied rename \" + src.getSrc() + \"(\" + src + \") to \" + dst\n              .getSrc() + \"(\" + dst + \") Reason=\" + e.getMessage());\n    } catch (InterruptedException e) {\n      Thread.currentThread().interrupt();\n      throw new InterruptedIOException(\n          \"Router Federation Rename is interrupted while checking permission.\");\n    }\n  }\n\n  private void checkRenamePermission(RemoteLocation srcLoc,\n      RemoteLocation dstLoc) throws IOException {\n    // check src path permission.\n    Path srcPath =\n        new Path(\"hdfs://\" + srcLoc.getNameserviceId() + srcLoc.getDest());\n    srcPath.getFileSystem(conf).access(srcPath.getParent(), FsAction.WRITE);\n    // check dst path permission.\n    Path dstPath =\n        new Path(\"hdfs://\" + dstLoc.getNameserviceId() + dstLoc.getDest());","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/java/org/apache/hadoop/hdfs/server/federation/router/RouterFederationRename.java#L148-L184","documentation":"Before submitting a fed rename, RouterFederationRename.checkPermission verifies the caller has write access to the parent directories of both src and dst in the actual subclusters. Any AccessControlException from that check (HDFS permissions, or kerberos proxy-user impersonation being refused) is rethrown with this message that records src/dst RemoteLocations and the underlying reason.","triggerScenarios":"checkPermission runs as the caller (directly in simple auth, or via UserGroupInformation.createProxyUser(remoteUserName, loginUser).doAs in kerberos): the underlying checkRenamePermission calls FileSystem.access(path.getParent(), FsAction.WRITE) on 'hdfs://<nameservice>/...' for both sides; lacking WRITE on either parent, or the router user not being allowed to proxy for the remote user, throws.","commonSituations":"User without write permission on the destination parent; ownership differs between subclusters; hadoop.proxyuser.<router-user>.groups/hosts not configured so the kerberos proxy doAs fails; running rename as a service account that only has read access.","solutions":["Check the Reason= suffix: it carries the original AccessControlException (permission vs proxying)","Grant WRITE on the parent directories of both src and dst in their respective subclusters (hdfs dfs -chmod / hdfs dfs -chown)","If the reason is proxy-user refusal, configure hadoop.proxyuser.<routerUser>.hosts/groups to cover the client, then restart the Namenode/refresh proxy user mappings","Retry the rename as a user that owns or can write both parent directories"],"exampleFix":"# before: destination parent not writable by caller\nhdfs dfs -fs hdfs://ns1 -ls -d /target        # owned by other:user, mode 755\n# after\nhdfs dfs -fs hdfs://ns1 -chmod 777 /target   # or chown to the calling user, or use hdfs dfs -setfacl","handlingStrategy":"try-catch","validationCode":"// Pre-check WRITE on both parents in their subclusters, mirroring the router's check\nfor (RemoteLocation loc : new RemoteLocation[]{srcLoc, dstLoc}) {\n  Path p = new Path(\"hdfs://\" + loc.getNameserviceId() + loc.getDest());\n  p.getFileSystem(conf).access(p.getParent(), FsAction.WRITE);\n}","typeGuard":null,"tryCatchPattern":"try {\n  dfs.rename(src, dst);\n} catch (AccessControlException ace) {\n  if (ace.getMessage() != null && ace.getMessage().startsWith(\"Permission denied rename\")) {\n    // message embeds the original Reason=; fix WRITE on parents or proxy-user config accordingly\n  }\n  throw ace;\n}","preventionTips":["Ensure the renaming user (or the proxied remote user) has WRITE on both parent directories in both subclusters","In kerberos deployments, configure hadoop.proxyuser.<routerUser>.hosts/groups correctly","Surface the Reason= suffix to operators - it distinguishes HDFS perms from proxy-user refusal"],"tags":["hdfs","router","federation","rename","permission-denied","access-control","kerberos-proxy"],"backgroundTag":"permission-denied","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}