{"record":{"id":"94007f5874b686c2","repo":"apereo/cas","slug":"located-claim-mapped-to-attribute-yet-r","errorCode":null,"errorMessage":"Located claim [{}] mapped to attribute [{}], yet resolved attributes [{}] do not contain attribute [{}]","messagePattern":"Located claim \\[(.+?)\\] mapped to attribute \\[(.+?)\\], yet resolved attributes \\[(.+?)\\] do not contain attribute \\[(.+?)\\]","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"support/cas-server-support-oidc-core/src/main/java/org/apereo/cas/oidc/claims/BaseOidcScopeAttributeReleasePolicy.java","lineNumber":107,"sourceCode":"                    LOGGER.debug(\"Mapped attribute [{}] to [{}] from script\", claim, result);\n                    return Pair.of(claim, result);\n                }\n            }\n\n            if (resolvedAttributes.containsKey(mappedAttr)) {\n                val value = resolvedAttributes.get(mappedAttr);\n                LOGGER.debug(\"Found mapped attribute [{}] with value [{}] for claim [{}]\", mappedAttr, value, claim);\n                return Pair.of(claim, value);\n            }\n            if (resolvedAttributes.containsKey(claim)) {\n                val value = resolvedAttributes.get(claim);\n                LOGGER.debug(\"CAS is unable to find the attribute [{}] that is mapped to claim [{}]. \"\n                        + \"However, since resolved attributes [{}] already contain this claim, \"\n                        + \"CAS will use [{}] with value(s) [{}]\",\n                    mappedAttr, claim, resolvedAttributes, claim, value);\n                return Pair.of(claim, value);\n            }\n            LOGGER.warn(\"Located claim [{}] mapped to attribute [{}], yet \"\n                    + \"resolved attributes [{}] do not contain attribute [{}]\",\n                claim, mappedAttr, resolvedAttributes, mappedAttr);\n        }\n\n        val value = resolvedAttributes.get(claim);\n        LOGGER.debug(\"No mapped attribute is defined for claim [{}]; Used [{}] to locate value [{}]\", claim, claim, value);\n        return Pair.of(claim, value);\n    }\n\n    @Override\n    public Map<String, List<Object>> getAttributesInternal(final RegisteredServiceAttributeReleasePolicyContext context,\n                                                           final Map<String, List<Object>> attributes) {\n        val resolvedAttributes = new TreeMap<String, List<Object>>(String.CASE_INSENSITIVE_ORDER);\n        resolvedAttributes.putAll(attributes);\n\n        val attributesToRelease = new HashMap<String, List<Object>>(attributes.size());\n        LOGGER.debug(\"Attempting to map and filter claims based on resolved attributes [{}]\", resolvedAttributes);\n","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-oidc-core/src/main/java/org/apereo/cas/oidc/claims/BaseOidcScopeAttributeReleasePolicy.java#L89-L125","documentation":"In BaseOidcScopeAttributeReleasePolicy.mapClaimToAttribute, a claim is mapped to a source attribute name via the claims-to-attributes mapping, but the resolved principal attributes do not contain an attribute under that mapped name. CAS logs a warning and continues without releasing a value for that claim, so the resulting ID/access token will omit the claim even though the scope requested it.","triggerScenarios":"Calling getAttributesInternal (during token/ID token generation for an OIDC service) when the service's oidcClaims mapping maps a claim (e.g. 'email') to an attribute name (e.g. 'mail') that does not exist in the principal's resolved attribute set.","commonSituations":"Mismatch between the LDAP/SAML attribute names released by the attribute repository and the attribute names configured in the OIDC service's claim mapping; user records missing the attribute; typo in the mapped attribute name in the service JSON.","solutions":["Fix the claim mapping in the OIDC registered service so each claim maps to the actual attribute name present on the principal.","Ensure the attribute source (e.g. LDAP attribute 'mail') is released/fetched for the user and named consistently.","Alternatively remove the mapped attribute name so the claim is looked up directly from resolved attributes by claim name."],"exampleFix":"// before (service json)\n\"oidcClaims\": { \"@class\": \"java.util.TreeMap\", \"email\": \"mail\" }\n// after - map to the attribute actually resolved, or drop the mapping\n\"oidcClaims\": { \"@class\": \"java.util.TreeMap\", \"email\": \"email\" }","handlingStrategy":"validation","validationCode":"// Before relying on a mapped claim, check the attribute exists on the principal\nMap<String, List<Object>> resolved = principal.getAttributes();\nif (!resolved.containsKey(mappedAttr)) {\n    LOGGER.warn(\"Mapped attribute {} missing for principal {}\", mappedAttr, principal.getId());\n}","typeGuard":"boolean hasMappedAttribute(Principal p, String mappedAttr) {\n    return p != null && p.getAttributes() != null && p.getAttributes().containsKey(mappedAttr);\n}","tryCatchPattern":null,"preventionTips":["Keep the claims->attribute mapping in service JSON synchronized with actual attribute source names","Audit released attributes per user after LDAP/source changes","Prefer mapping claims to the same-named attribute to avoid indirection"],"tags":["oidc","attributes","claim-mapping","config"],"backgroundTag":"resource-not-found","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}