apereo/cas · warning
e.getMessage() (ResourceNotFoundException logged during…
Error message
e.getMessage() (ResourceNotFoundException logged during deleteAll)
What it means
DynamoDbTicketRegistryFacilitator.deleteAll() runs a batch deletion of all tickets via a deletor callable. If DynamoDB throws ResourceNotFoundException (the ticket table does not exist), the code logs the exception message at WARN, recreates the missing ticket tables via createTicketTables(false), and retries the deletion once. The error item here is the WARN log line — an application-level recovery, not a thrown exception to callers.
Solutions
- Let the built-in recovery work: the registry recreates tables and retries; confirm logs show 'createTicketTables' succeeding afterwards
- Verify cas.ticket.registry.dynamo-db settings (region, endpoint, table prefix) match the actual DynamoDB environment
- Check AWS IAM permissions for CreateTable/DeleteItem on the configured tables
- If tables were deleted intentionally, restart CAS or trigger table creation so state is consistent
- For local dev, start the DynamoDB test container (ci tests) before running registry operations
Example fix
// before: region mismatch — table exists in us-east-1, CAS looks in eu-west-1 # cas.ticket.registry.dynamo-db.region=eu-west-1 // after cas.ticket.registry.dynamo-db.region=us-east-1
Defensive patterns
Strategy: retry
Validate before calling
// Before deleteAll, confirm the table exists:
DescribeTableRequest req = DescribeTableRequest.builder()
.tableName(tableName).build();
dynamoDbClient.describeTable(req); // throws ResourceNotFoundException if missing Try / catch
try {
return deletor.get();
} catch (ResourceNotFoundException e) {
LOGGER.warn(e.getMessage(), e);
createTicketTables(false); // recreate, then retry once
return deletor.get();
} Prevention
- Pin the AWS region and endpoint configuration used by the ticket registry
- Grant IAM permissions for both DescribeTable/CreateTable and item operations
- Use a consistent table prefix across all CAS nodes
- In dev, keep the DynamoDB local container volume persistent so tables survive restarts
When it happens
Trigger: Calling deleteAll() (e.g. purge-all tickets operation or scheduled cleanup) when the DynamoDB table backing the ticket registry does not exist: fresh environment before table auto-creation, tables deleted manually in AWS console, wrong region/profile/table-prefix configuration pointing to a nonexistent table, or IAM/region mismatch.
Common situations: Deploying CAS against a new DynamoDB account/region without letting CAS create its tables; someone dropped the CAS ticket tables; cas.ticket.registry.dynamo-db table-prefix mismatch between nodes; using a DynamoDB endpoint (local test container) that was wiped between runs.
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
- No ticket definition could be found in the catalog to match
- No authentication found for ticket
- Unable to accept the ID token with an invalid [sub] claim
- Invalid token:
- Invalid token:
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/ff579118a2152ad0.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-dynamodb-ticket-registry/src/main/java/org/apereo/cas/ticket/registry/DynamoDbTicketRegistryFacilitator.java:164
* @return the int
*/
public int deleteAll() {
val deletor = new Supplier<Integer>() {
@Override
public Integer get() {
val count = new AtomicInteger();
val metadata = ticketCatalog.findAll();
metadata.forEach(definition -> {
val tableName = definition.getProperties().getStorageName();
count.addAndGet(Math.toIntExact(deleteTickets(tableName, scanTicketIds(tableName))));
});
return count.get();
}
};
try {
return deletor.get();
} catch (final ResourceNotFoundException e) {
LOGGER.warn(e.getMessage(), e);
createTicketTables(false);
return deletor.get();
}
}
/**
* Scan and paginate.
*
* @return the stream
*/
public Stream<Ticket> stream() {
val metadata = ticketCatalog.findAll();
val resultStreams = metadata
.stream()
.map(defn -> queryTicketsByIndex(defn.getProperties().getStorageName(),
PREFIX_INDEX_NAME, ColumnNames.PREFIX, defn.getPrefix(), 0, true))
.toList();
return Streams.concat(resultStreams.toArray(new Stream[0]));View on GitHub (pinned to e7288fc434)