{"record":{"id":"e103ac2be46f4a3b","repo":"alibaba/nacos","slug":"user-username-already-bound-to-the-role-role","errorCode":null,"errorMessage":"user '{username}' already bound to the role '{role}'!","messagePattern":"user '(.+?)' already bound to the role '(.+?)'!","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"info","filePath":"plugin-default-impl/nacos-default-auth-plugin/src/main/java/com/alibaba/nacos/plugin/auth/impl/roles/NacosRoleServiceDirectImpl.java","lineNumber":140,"sourceCode":"    \n    @Override\n    public void addRole(String role, String username) {\n        if (userDetailsService.getUser(username) == null) {\n            throw new IllegalArgumentException(\"user '\" + username + \"' not found!\");\n        }\n        \n        if (AuthConstants.GLOBAL_ADMIN_ROLE.equals(role)) {\n            throw new IllegalArgumentException(\n                \"role '\" + AuthConstants.GLOBAL_ADMIN_ROLE + \"' is not permitted to create!\");\n        }\n        \n        if (AuthConstants.ANONYMOUS_ROLE.equals(role)) {\n            throw new IllegalArgumentException(\n                \"role '\" + AuthConstants.ANONYMOUS_ROLE + \"' is reserved by the system\");\n        }\n        \n        if (isUserBoundToRole(role, username)) {\n            throw new IllegalArgumentException(\n                \"user '\" + username + \"' already bound to the role '\" + role + \"'!\");\n        }\n        \n        rolePersistService.addRole(role, username);\n        getCachedRoleSet().add(role);\n        invalidateUserRoles(username);\n    }\n    \n    @Override\n    public void addAdminRole(String username) {\n        if (userDetailsService.getUser(username) == null) {\n            throw new IllegalArgumentException(\"user '\" + username + \"' not found!\");\n        }\n        if (hasGlobalAdminRole()) {\n            throw new IllegalArgumentException(\n                \"role '\" + AuthConstants.GLOBAL_ADMIN_ROLE + \"' already exist !\");\n        }\n        ","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/alibaba/nacos/blob/9b989acdf181d00898f2e8839257bb2b2a3cefe3/plugin-default-impl/nacos-default-auth-plugin/src/main/java/com/alibaba/nacos/plugin/auth/impl/roles/NacosRoleServiceDirectImpl.java#L122-L158","documentation":"Thrown by addRole when isUserBoundToRole(role, username) is already true, i.e. the user already holds that exact role. Nacos rejects duplicate role bindings to keep the role set unique and avoid redundant permission inheritance. The check runs after the reserved-role and existence checks, just before persisting.","triggerScenarios":"Calling addRole for a role the user already has; double-submitting a role-grant form; a retry loop that re-runs a successful grant after a transient error; idempotency-unaware provisioning scripts.","commonSituations":"See trigger scenarios.","solutions":["Before granting, check roleService.getRoles(username) (or isUserBoundToRole) and skip if already present.","Make provisioning idempotent: treat 'already bound' as success rather than retrying.","Guard the UI/submit button against duplicate submissions."],"exampleFix":"// before\nroleService.addRole(role, username); // throws if already bound\n\n// after\nif (!roleService.isUserBoundToRole(role, username)) {\n    roleService.addRole(role, username);\n}","handlingStrategy":"validation","validationCode":"if (roleService.isUserBoundToRole(role, username)) {\n    // already granted; treat as success (idempotent)\n    return;\n}\nroleService.addRole(role, username);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Make role-grant operations idempotent by checking existing bindings first.","Disable submit buttons after first click to prevent duplicate requests.","In retry loops, treat 'already bound' as a successful terminal state."],"tags":["auth","role","duplicate","idempotency"],"backgroundTag":null,"analyzedSha":"9b989acdf181d00898f2e8839257bb2b2a3cefe3","analyzedAt":"2026-08-14T07:17:31.569Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}