apereo/cas · warning

Located claim [ ] mapped to attribute [ ], yet resolved…

Error message

Located claim [{}] mapped to attribute [{}], yet resolved attributes [{}] do not contain attribute [{}]

What it means

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.

Solutions

  1. Fix the claim mapping in the OIDC registered service so each claim maps to the actual attribute name present on the principal.
  2. Ensure the attribute source (e.g. LDAP attribute 'mail') is released/fetched for the user and named consistently.
  3. Alternatively remove the mapped attribute name so the claim is looked up directly from resolved attributes by claim name.

Example fix

// before (service json)
"oidcClaims": { "@class": "java.util.TreeMap", "email": "mail" }
// after - map to the attribute actually resolved, or drop the mapping
"oidcClaims": { "@class": "java.util.TreeMap", "email": "email" }
Defensive patterns

Strategy: validation

Validate before calling

// Before relying on a mapped claim, check the attribute exists on the principal
Map<String, List<Object>> resolved = principal.getAttributes();
if (!resolved.containsKey(mappedAttr)) {
    LOGGER.warn("Mapped attribute {} missing for principal {}", mappedAttr, principal.getId());
}

Type guard

boolean hasMappedAttribute(Principal p, String mappedAttr) {
    return p != null && p.getAttributes() != null && p.getAttributes().containsKey(mappedAttr);
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/94007f5874b686c2. Report an issue: GitHub.

Appendix: source

Thrown at support/cas-server-support-oidc-core/src/main/java/org/apereo/cas/oidc/claims/BaseOidcScopeAttributeReleasePolicy.java:107

                    LOGGER.debug("Mapped attribute [{}] to [{}] from script", claim, result);
                    return Pair.of(claim, result);
                }
            }

            if (resolvedAttributes.containsKey(mappedAttr)) {
                val value = resolvedAttributes.get(mappedAttr);
                LOGGER.debug("Found mapped attribute [{}] with value [{}] for claim [{}]", mappedAttr, value, claim);
                return Pair.of(claim, value);
            }
            if (resolvedAttributes.containsKey(claim)) {
                val value = resolvedAttributes.get(claim);
                LOGGER.debug("CAS is unable to find the attribute [{}] that is mapped to claim [{}]. "
                        + "However, since resolved attributes [{}] already contain this claim, "
                        + "CAS will use [{}] with value(s) [{}]",
                    mappedAttr, claim, resolvedAttributes, claim, value);
                return Pair.of(claim, value);
            }
            LOGGER.warn("Located claim [{}] mapped to attribute [{}], yet "
                    + "resolved attributes [{}] do not contain attribute [{}]",
                claim, mappedAttr, resolvedAttributes, mappedAttr);
        }

        val value = resolvedAttributes.get(claim);
        LOGGER.debug("No mapped attribute is defined for claim [{}]; Used [{}] to locate value [{}]", claim, claim, value);
        return Pair.of(claim, value);
    }

    @Override
    public Map<String, List<Object>> getAttributesInternal(final RegisteredServiceAttributeReleasePolicyContext context,
                                                           final Map<String, List<Object>> attributes) {
        val resolvedAttributes = new TreeMap<String, List<Object>>(String.CASE_INSENSITIVE_ORDER);
        resolvedAttributes.putAll(attributes);

        val attributesToRelease = new HashMap<String, List<Object>>(attributes.size());
        LOGGER.debug("Attempting to map and filter claims based on resolved attributes [{}]", resolvedAttributes);

View on GitHub (pinned to e7288fc434)