{"record":{"id":"b48110e6dc208daf","repo":"spring-projects/spring-security","slug":"access-is-denied-b48110","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/AffirmativeBased.java","lineNumber":76,"sourceCode":"\t@Override\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tpublic void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)\n\t\t\tthrows AccessDeniedException {\n\t\tint deny = 0;\n\t\tfor (AccessDecisionVoter voter : getDecisionVoters()) {\n\t\t\tint result = voter.vote(authentication, object, configAttributes);\n\t\t\tswitch (result) {\n\t\t\t\tcase AccessDecisionVoter.ACCESS_GRANTED:\n\t\t\t\t\treturn;\n\t\t\t\tcase AccessDecisionVoter.ACCESS_DENIED:\n\t\t\t\t\tdeny++;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (deny > 0) {\n\t\t\tthrow new AccessDeniedException(\n\t\t\t\t\tthis.messages.getMessage(\"AbstractAccessDecisionManager.accessDenied\", \"Access is denied\"));\n\t\t}\n\t\t// To get this far, every AccessDecisionVoter abstained\n\t\tcheckAllowIfAllAbstainDecisions();\n\t}\n\n}\n","sourceCodeStart":58,"sourceCodeEnd":84,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/access/src/main/java/org/springframework/security/access/vote/AffirmativeBased.java#L58-L84","documentation":"AffirmativeBased's decide() grants access as soon as any AccessDecisionVoter votes ACCESS_GRANTED; it only throws this AccessDeniedException when no voter granted access AND at least one voted ACCESS_DENIED (deny > 0). It fires when the authenticated user's authorities satisfy none of the voters (e.g. RoleVoter/PreInvocationAuthorizationAdviceVoter) for the secured invocation, so the deny votes carry the decision. If all voters abstained, decide() returns without exception instead.","triggerScenarios":"During method/web security checks, one AccessDecisionVoter returns ACCESS_DENIED for the invocation even though others may have granted.","commonSituations":"A user lacks one of several required roles while another role matched (e.g. @PreAuthorize replaced by role voters with overlapping attributes); misconfigured voter denies attributes it should abstain on.","solutions":["Grant the user the missing role/authority the denying voter requires","Remove or adjust the voter/attribute that inappropriately denies","Switch strategy to ConsensusBased or UnanimousBased if a single deny should not block","Log each voter's decision to identify which voter denied"],"exampleFix":"// before\n<intercept-url pattern=\"/admin/**\" access=\"ROLE_ADMIN,ROLE_USER\"/>\n// user has ROLE_USER only; RoleVoter denies ROLE_ADMIN\n\n// after\n<intercept-url pattern=\"/admin/**\" access=\"ROLE_ADMIN\"/>\n// or grant the user ROLE_ADMIN","handlingStrategy":"try-catch","validationCode":"boolean hasAllRoles(Authentication a, List<String> roles) {\n    var granted = a.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet());\n    return granted.containsAll(roles);\n}","typeGuard":"null","tryCatchPattern":"try {\n    affirmativeBased.decide(auth, object, attrs);\n} catch (AccessDeniedException e) {\n    throw new ResponseStatusException(HttpStatus.FORBIDDEN, \"A voter denied access\");\n}","preventionTips":["Grant users the full role sets referenced by security attributes","Audit for voters that deny attributes they should abstain on","Log voter decisions in staging to catch unexpected denies"],"tags":["spring-security","authorization","affirmative-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-14T11:17:12.474Z"}