apereo/cas · info

Registered service [ ] has expired on [ ]

Error message

Registered service [{}] has expired on [{}]

What it means

AbstractServicesManager periodically evaluates each registered service's expiration policy (checkServiceExpirationPolicyIfAny). When the expiration date has passed, processExpiredRegisteredService logs a warning and, per policy flags, notifies contacts (publishing CasRegisteredServiceExpiredEvent) and/or deletes the service from the registry. The message itself is informational: the service is expired as of the policy's expiration date.

Solutions

  1. Update or remove the expirationDate in the service's expiration policy (or set a future date) if the service should remain active
  2. Set notifyWhenExpired=true to alert service contacts before/upon expiry
  3. Check whether deleteWhenExpired=true removed the service from the registry and restore it if deletion was unintended
  4. Verify server clocks/NTP to rule out false expiry from skew

Example fix

// before: service expired
// "expirationPolicy":{"@class":"...ServiceTimeBasedExpirationPolicy","expirationDate":"2025-01-01"}
// after: extend expiration
// "expirationPolicy":{"@class":"...ServiceTimeBasedExpirationPolicy","expirationDate":"2027-01-01","notifyWhenExpired":true}
Defensive patterns

Strategy: validation

Validate before calling

RegisteredServiceExpirationPolicy p = service.getExpirationPolicy();
if (p != null && p.isExpired()) {
    LOGGER.warn("Service {} expires/is expired on {}", service.getName(), p.getExpirationDate());
}

Type guard

boolean expiringSoon(RegisteredService s, java.time.LocalDate threshold) {
    return s.getExpirationPolicy() instanceof RegisteredServiceTimeBasedExpirationPolicy t
        && t.getExpirationDate() != null && t.getExpirationDate().isBefore(threshold);
}

Prevention

When it happens

Trigger: ServicesManager's scheduled expiration check finds registeredService.getExpirationPolicy().isExpired() true — the service definition carries an expirationDate earlier than now, with optional notifyWhenExpired/deleteWhenExpired flags controlling downstream behavior.

Common situations: Service definitions imported from another environment carried stale expiration dates; a temporary service was never extended; clock skew between nodes; admins unaware that deleteWhenExpired=true silently removed services from the registry.

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/f3f917a118dc7b06. Report an issue: GitHub.

Appendix: source

Thrown at core/cas-server-core-services-registry/src/main/java/org/apereo/cas/services/mgmt/AbstractServicesManager.java:487

        @Nullable final RegisteredService registeredService) {
        val result = checkServiceExpirationPolicyIfAny(registeredService);
        if (validateAndFilterServiceByEnvironment(result)) {
            return result;
        }
        return null;
    }

    private @Nullable RegisteredService checkServiceExpirationPolicyIfAny(
        @Nullable final RegisteredService registeredService) {
        if (registeredService == null || RegisteredServiceAccessStrategyUtils.ensureServiceIsNotExpired(registeredService)) {
            return registeredService;
        }
        return processExpiredRegisteredService(registeredService);
    }

    private @Nullable RegisteredService processExpiredRegisteredService(final RegisteredService registeredService) {
        val policy = registeredService.getExpirationPolicy();
        LOGGER.warn("Registered service [{}] has expired on [{}]", registeredService.getServiceId(), policy.getExpirationDate());
        val clientInfo = ClientInfoHolder.getClientInfo();
        if (policy.isNotifyWhenExpired()) {
            LOGGER.debug("Contacts for registered service [{}] will be notified of service expiry", registeredService.getServiceId());
            publishEvent(new CasRegisteredServiceExpiredEvent(this, registeredService, false, clientInfo));
        }
        if (policy.isDeleteWhenExpired()) {
            LOGGER.debug("Deleting expired registered service [{}] from registry.", registeredService.getServiceId());
            if (policy.isNotifyWhenDeleted()) {
                LOGGER.debug("Contacts for registered service [{}] will be notified of service expiry and removal",
                    registeredService.getServiceId());
                publishEvent(new CasRegisteredServiceExpiredEvent(this, registeredService, true, clientInfo));
            }
            delete(registeredService);
            return null;
        }
        return registeredService;
    }

View on GitHub (pinned to e7288fc434)