{"record":{"id":"bb9cb54e6e7ba91a","repo":"apereo/cas","slug":"no-expiration-policy-could-be-found-by-the-name","errorCode":null,"errorMessage":"No expiration policy could be found by the name [{}] for ticket state [{}]","messagePattern":"No expiration policy could be found by the name \\[(.+?)\\] for ticket state \\[(.+?)\\]","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"core/cas-server-core-tickets-api/src/main/java/org/apereo/cas/ticket/expiration/BaseDelegatingExpirationPolicy.java","lineNumber":119,"sourceCode":"        LOGGER.trace(\"Getting TTL from policy [{}] for ticket [{}]\", policy.getName(), ticketState);\n        return policy.getTimeToLive(ticketState);\n    }\n\n    @JsonIgnore\n    @Override\n    public Long getTimeToLive() {\n        return this.policies.get(POLICY_NAME_DEFAULT).getTimeToLive();\n    }\n\n    protected Optional<ExpirationPolicy> getExpirationPolicyFor(final AuthenticationAwareTicket ticketState) {\n        val name = getExpirationPolicyNameFor(ticketState);\n        LOGGER.trace(\"Received expiration policy name [{}] to activate\", name);\n        if (StringUtils.isNotBlank(name) && policies.containsKey(name)) {\n            val policy = policies.get(name);\n            LOGGER.trace(\"Located expiration policy [{}] by name [{}]\", policy, name);\n            return Optional.of(policy);\n        }\n        LOGGER.warn(\"No expiration policy could be found by the name [{}] for ticket state [{}]\", name, ticketState);\n        return Optional.empty();\n    }\n\n    protected abstract String getExpirationPolicyNameFor(AuthenticationAwareTicket ticketState);\n\n    @Override\n    public ZonedDateTime toMaximumExpirationTime(final Ticket ticketState) {\n        val result = getExpirationPolicyFor((AuthenticationAwareTicket) ticketState);\n        return result.map(policy -> policy.toMaximumExpirationTime(ticketState))\n            .orElseGet(() -> ZonedDateTime.now(Clock.systemUTC()));\n    }\n}\n","sourceCodeStart":101,"sourceCodeEnd":132,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/core/cas-server-core-tickets-api/src/main/java/org/apereo/cas/ticket/expiration/BaseDelegatingExpirationPolicy.java#L101-L132","documentation":"This is the low-level lookup inside BaseDelegatingExpirationPolicy.getExpirationPolicyFor(): the name produced for a ticket state is blank or absent from the `policies` map, so it logs a warning and returns Optional.empty(). Callers (isExpired, getTimeToLive, toMaximumExpirationTime) then fall back to default behavior. It is a configuration/naming mismatch signal, not a thrown exception.","triggerScenarios":"getExpirationPolicyFor is invoked during any ticket expiration check when getExpirationPolicyNameFor(ticketState) returns a name that is blank or not a key of the policies map (names compared exactly via policies.containsKey).","commonSituations":"Typos between the name passed to addPolicy(name, policy) and the name the predicate produces; policy map reset by JSON deserialization; custom subclass returning null when no predicate matches.","solutions":["Log/print getExpirationPolicyNameFor(state) and the policies keySet; align the predicate's returned name with a registered key.","Register the missing policy under the exact name, or add a DEFAULT policy as catch-all.","Fix the custom predicate to return POLICY_NAME_DEFAULT instead of null/blank when nothing matches.","If policies were lost in serialization, re-add them after deserialization or persist the full policy object."],"exampleFix":"// before\nString name = attributes.get(\"policyName\"); // null for most users\n// after\nString name = attributes.getOrDefault(\"policyName\", BaseDelegatingExpirationPolicy.POLICY_NAME_DEFAULT);","handlingStrategy":"validation","validationCode":"val keys = policy.getPolicies().keySet(); val chosen = policy.getExpirationPolicyNameFor(ticket); log.debug(\"chosen={} keys={}\", chosen, keys); if (chosen == null || !keys.contains(chosen)) { registerMissingPolicy(chosen); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Exact-match names: policies.containsKey is case-sensitive — use constants, not literals","Return POLICY_NAME_DEFAULT from custom getExpirationPolicyNameFor implementations instead of null","Re-check policy registration after any change to ticket serialization format"],"tags":["cas","expiration-policy","lookup-failure","misconfiguration"],"backgroundTag":"missing-config-key","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"}