apereo/cas · warning
warn(logger, getMessage(throwable), throwable)
Error message
warn(logger, getMessage(throwable), throwable)
What it means
In AbstractTicketRegistry.getTicket, when the retrieved ticket is expired, the registry attempts to delete it and (for TGTs) publish a CasTicketGrantingTicketDestroyedEvent. Any exception during that cleanup is swallowed and logged at warn level via LoggingUtils.warn(logger, throwable). Operationally the getTicket still returns no ticket; this warning indicates the expired-ticket cleanup path failed.
Solutions
- Inspect the attached throwable (logged via LoggingUtils.warn) to find the root cause — usually ticket-registry backend connectivity or serialization.
- Verify the ticket registry store (Redis/Mongo/etc.) is reachable and credentials/network are healthy.
- Check registered CasTicketGrantingTicketDestroyedEvent listeners for exceptions they throw; fix or make them defensive.
- If stale/deserialization-prone entries accumulate, clean the registry of old tickets; the warning is non-fatal to the caller (ticket is treated as absent).
Example fix
// before
try { deleteTicket(ticket); ... } catch (final Exception e) { LoggingUtils.warn(LOGGER, e); } // hides backend outage
// after
// monitor LOGGER.warn from AbstractTicketRegistry and alert on backend exceptions:
// add health checks/retries for the ticket registry datasource (e.g. Redis ping) instead of relying on swallowed cleanup errors Defensive patterns
Strategy: try-catch
Try / catch
// caller: expired ticket simply returns null; guard the null
Ticket t = ticketRegistry.getTicket(id);
if (t == null) { /* treat as unauthenticated; also alert on AbstractTicketRegistry warn logs */ } Prevention
- Monitor warn logs from AbstractTicketRegistry as a signal of ticket-registry backend trouble
- Keep CasTicketGrantingTicketDestroyedEvent listeners exception-safe
- Add health checks and retries for the ticket registry store
When it happens
Trigger: Calling ticketRegistry.getTicket(id) for an expired ticket where deleteTicket(ticket) or the destroyed-event publication throws — e.g. underlying storage (Redis/Mongo/JDBC/Hazelcast) unreachable, serialization failure, or listener error during event publish.
Common situations: Transient backend outages during high-traffic validation; deserialization errors of stale tickets in the registry; event listeners throwing inside CasTicketGrantingTicketDestroyedEvent handlers.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- InvalidTicketException
- Found removable encoded ticket
- Could not grant service ticket
- No authentication found for ticket
- Principal attribute [
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/82846a13828b0692.
Report an issue: GitHub.
Appendix: source
Thrown at core/cas-server-core-tickets-api/src/main/java/org/apereo/cas/ticket/registry/AbstractTicketRegistry.java:124
@Override
public @Nullable Ticket getTicket(final String ticketId) {
val returnTicket = getTicket(ticketId, ticket -> {
if (ticket.isExpired()) {
val ticketAgeSeconds = getTicketAgeSeconds(ticket);
LOGGER.debug("Ticket [{}] has expired according to policy [{}] after [{}] seconds and [{}] uses and will be removed from the ticket registry",
ticketId, ticket.getExpirationPolicy().getName(), ticketAgeSeconds, ticket.getCountOfUses());
val clientInfo = ClientInfoHolder.getClientInfo();
if (ticket instanceof final TicketGrantingTicket tgt) {
applicationContext.publishEvent(new CasRequestSingleLogoutEvent(this, tgt, clientInfo));
}
try {
deleteTicket(ticket);
if (ticket instanceof final TicketGrantingTicket tgt) {
applicationContext.publishEvent(new CasTicketGrantingTicketDestroyedEvent(this, tgt, clientInfo));
}
} catch (final Exception e) {
LoggingUtils.warn(LOGGER, e);
}
return false;
}
return true;
});
if (returnTicket != null) {
val ticketAgeSeconds = getTicketAgeSeconds(returnTicket);
if (ticketAgeSeconds < -1) {
LOGGER.warn("Ticket created [{}] second(s) in the future. Check time synchronization on all servers.", ticketAgeSeconds * -1);
}
}
return returnTicket;
}
@Override
public <T extends Ticket> T getTicket(final String ticketId, final @NonNull Class<T> clazz) {
val ticket = getTicket(ticketId);
if (ticket == null) {View on GitHub (pinned to e7288fc434)