apereo/cas · warning
Unable to locate ticket map for ticket metadata
Error message
Unable to locate ticket map for ticket metadata [{}] What it means
In HazelcastTicketRegistry.addSingleTicket, after resolving the ticket's TicketMetadata from the catalog, the code looks up the corresponding Hazelcast IMap ('ticket map') that should hold tickets of that type. When no map is registered/found for the metadata, the ticket is NOT stored (ticketMap.set is skipped) and a warning is logged instead. The call returns the ticket normally, so persistence is silently skipped.
Solutions
- Ensure every ticket type in the TicketDefinition catalog has a corresponding Hazelcast map created during registry initialization.
- Check the ticket's metadata (prefix/name) against the configured map names in the Hazelcast ticket registry configuration.
- If using a custom ticket, register its definition and map in the catalog (TicketCatalogConfigurer) before use.
- Enable debug logging to inspect the metadata values being looked up and compare with initialized maps.
Example fix
// before
@Bean
public TicketCatalogConfigurer customTicketCatalog() {
return chain -> chain.register(new TicketDefinition()) /* missing map registration */;
}
// after — also register the backing map for the definition
@Bean
public HazelcastTicketRegistryConfigurer hazelcastMaps() {
return hz -> hz.getMap("customTicketMap");
} Defensive patterns
Strategy: validation
Validate before calling
// Ensure a map exists for the ticket type before adding
var metadata = ticketCatalog.findTicketDefinition(ticket).map(TicketDefinition::getProperties);
var mapName = ticketCatalog.findTicketDefinition(ticket)
.map(d -> d.getProperties().getStorageName()).orElse(null);
if (mapName == null || hzInstance.getMap(mapName) == null) {
throw new IllegalStateException("No Hazelcast map registered for ticket type " + ticket.getId());
} Type guard
TicketDefinition def = ticketCatalog.findTicketDefinition(ticketId); boolean hasMap = def != null && def.getProperties() != null && def.getProperties().getStorageName() != null;
Prevention
- Register every custom ticket definition AND its backing Hazelcast map in the same configurer.
- After upgrading CAS, diff your TicketCatalog/Hazelcast map configuration against the new defaults.
- Treat this warning as a persistence-loss alarm: monitor logs and fail health checks if it appears.
- Write an integration test that adds and reads each ticket type in your catalog.
When it happens
Trigger: addSingleTicket(ticket) when TicketDefinition catalog contains the ticket type (metadata resolved) but there is no Hazelcast map instance matching that definition — e.g. the map was never created because the ticket type is new/custom or the registry was configured with maps for only certain ticket types.
Common situations: Adding a custom ticket type without defining a matching Hazelcast map; runtime catalog changes after registry initialization; creating tickets via an extension (e.g. MFA, webflow custom tickets) whose maps aren't registered; config where map names and ticket catalog prefixes drift apart after version upgrade.
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
- Final ticket id [ ] length [ ] exceeds [ ] characters
- Ticket passed is null and cannot be decoded
- Using Hazelcast WAN Replication requires a Hazelcast…
- No ticket definition could be found in the catalog to match
- No user can be accepted because none is defined
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/f4f0c5bcd008de9d.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-hazelcast-ticket-registry/src/main/java/org/apereo/cas/ticket/registry/HazelcastTicketRegistry.java:95
val metadata = ticketCatalog.find(ticket);
val ticketMap = getTicketMapInstanceByMetadata(metadata);
if (ticketMap != null) {
val holder = HazelcastTicketDocument
.builder()
.id(encTicket.getId())
.type(metadata.getImplementationClass().getName())
.principal(digestIdentifier(getPrincipalIdFrom(ticket)))
.timeToLive(ttl)
.ticket(encTicket)
.prefix(metadata.getPrefix())
.service(ticket instanceof final ServiceAwareTicket sat && Objects.nonNull(sat.getService()) ? sat.getService().getId() : null)
.attributes(collectAndDigestTicketAttributes(ticket))
.build();
ticketMap.set(encTicket.getId(), holder, ttl, TimeUnit.SECONDS);
LOGGER.debug("Added ticket [{}] with ttl [{}s]", encTicket.getId(), ttl);
} else {
LOGGER.warn("Unable to locate ticket map for ticket metadata [{}]", metadata);
}
return ticket;
}
@Override
public Ticket getTicket(final String ticketId, final Predicate<Ticket> predicate) {
val encTicketId = digestIdentifier(ticketId);
if (StringUtils.isBlank(encTicketId)) {
return null;
}
val metadata = ticketCatalog.find(ticketId);
if (metadata != null) {
val map = getTicketMapInstanceByMetadata(metadata);
if (map != null) {
val document = map.get(encTicketId);
if (document != null && document.getTicket() != null) {
val result = decodeTicket(document.getTicket());
if (predicate != null && predicate.test(result)) {View on GitHub (pinned to e7288fc434)