{"record":{"id":"364e5f072f1f88cd","repo":"spring-projects/spring-security","slug":"access-is-denied-364e5f","errorCode":null,"errorMessage":"Access is denied","messagePattern":"Access is denied","errorType":"exception","errorClass":"AccessDeniedException","httpStatus":403,"severity":"error","filePath":"access/src/main/java/org/springframework/security/access/vote/UnanimousBased.java","lineNumber":78,"sourceCode":"\t * @throws AccessDeniedException if access is denied\n\t */\n\t@Override\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tpublic void decide(Authentication authentication, Object object, Collection<ConfigAttribute> attributes)\n\t\t\tthrows AccessDeniedException {\n\t\tint grant = 0;\n\t\tList<ConfigAttribute> singleAttributeList = new ArrayList<>(1);\n\t\tsingleAttributeList.add(null);\n\t\tfor (ConfigAttribute attribute : attributes) {\n\t\t\tsingleAttributeList.set(0, attribute);\n\t\t\tfor (AccessDecisionVoter voter : getDecisionVoters()) {\n\t\t\t\tint result = voter.vote(authentication, object, singleAttributeList);\n\t\t\t\tswitch (result) {\n\t\t\t\t\tcase AccessDecisionVoter.ACCESS_GRANTED:\n\t\t\t\t\t\tgrant++;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase AccessDecisionVoter.ACCESS_DENIED:\n\t\t\t\t\t\tthrow new AccessDeniedException(this.messages\n\t\t\t\t\t\t\t.getMessage(\"AbstractAccessDecisionManager.accessDenied\", \"Access is denied\"));\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// To get this far, there were no deny votes\n\t\tif (grant > 0) {\n\t\t\treturn;\n\t\t}\n\t\t// To get this far, every AccessDecisionVoter abstained\n\t\tcheckAllowIfAllAbstainDecisions();\n\t}\n\n}\n","sourceCodeStart":60,"sourceCodeEnd":94,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/access/src/main/java/org/springframework/security/access/vote/UnanimousBased.java#L60-L94","documentation":"UnanimousBased.decide() throws AccessDeniedException as soon as any single relevant voter votes ACCESS_DENIED. Unanimous strategy requires every voter with a matching attribute to grant; one deny aborts immediately.","triggerScenarios":"Any voter returns ACCESS_DENIED for its matching config attribute during the per-attribute voting loop (each attribute is voted individually with a single-attribute list).","commonSituations":"User missing one of several roles required by a multi-attribute rule; prefix mismatch making RoleVoter deny unexpectedly; migrating from AffirmativeBased where a single grant masked the deny.","solutions":["Ensure the user holds ALL authorities referenced by the securing attributes","Fix voter configuration/prefix so unintended denies become abstentions","Switch to AffirmativeBased if any-grant semantics are desired","Enable debug logging for AbstractAccessDecisionManager to find the denying voter"],"exampleFix":"// before\n<intercept-url pattern=\"/**\" access=\"ROLE_A,ROLE_B\"/>\n// UnanimousBased: user with only ROLE_A is denied by the ROLE_B attribute\n\n// after\n<intercept-url pattern=\"/**\" access=\"ROLE_A or ROLE_B\"/>\n// or grant both roles","handlingStrategy":"try-catch","validationCode":"boolean unanimous(List<AccessDecisionVoter<?>> voters, Authentication a, Object o, List<ConfigAttribute> attrs) {\n    return attrs.stream().allMatch(attr -> voters.stream()\n        .filter(v -> v.supports(attr))\n        .allMatch(v -> v.vote(a, o, List.of(attr)) != AccessDecisionVoter.ACCESS_DENIED));\n}","typeGuard":"null","tryCatchPattern":"try {\n    unanimousBased.decide(auth, object, attrs);\n} catch (AccessDeniedException e) {\n    throw new ResponseStatusException(HttpStatus.FORBIDDEN, \"A required authority is missing\");\n}","preventionTips":["Ensure users hold every authority listed in multi-attribute rules","Prefer expression-based @PreAuthorize with 'or' semantics where any-of is intended","Enable voter debug logging to identify the single denying voter"],"tags":["spring-security","authorization","unanimous-based","voters","access-denied"],"backgroundTag":"permission-denied","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}