apereo/cas · warning

[ ] does not match the recommended pattern [ ]. While CAS…

Error message

[{}] does not match the recommended pattern [{}]. While CAS tries to be forgiving as much as possible, it's recommended that you rename the file to match the requested pattern to avoid issues with duplicate service loading. Future CAS versions may try to strictly force the naming syntax, refusing to load the file.

What it means

Service definition files must be named '<id>-<something>.<ext>' matching the registry's serviceFileNamePattern (id-based, e.g. 10000001-MyApp.json). If load(File) sees a file with a valid extension but a non-conforming name, CAS logs this warning and still loads it, but warns that duplicates and future strict enforcement may cause problems.

Solutions

  1. Rename the file to match the pattern '<numericId>-<serviceName>.json' (e.g. 10000001-MyApp.json).
  2. Ensure the numeric id in the filename matches the id inside the JSON to avoid duplicate-loading issues.
  3. Redeploy/mount the corrected files and reload the registry; confirm the warning disappears.

Example fix

// before
mv myapp.json /etc/cas/config/services/
// after
mv myapp.json /etc/cas/config/services/10000001-MyApp.json
Defensive patterns

Strategy: validation

Validate before calling

// Validate filename before dropping into services dir
String name = file.getName();
if (!name.matches("\\d+-[\\w.-]+\\.(json|yaml|yml)")) {
    throw new IllegalArgumentException("Rename to <numericId>-<serviceName>.json: " + name);
}

Prevention

When it happens

Trigger: Placing a file like 'myapp.json' or '10000001.json' (no dash-separated unique suffix) into the services directory, then having CAS scan/load it; RegexUtils.matches(serviceFileNamePattern, fileName) fails.

Common situations: Renaming files manually without following the CAS convention; migrating service definitions from another system; copy-paste of service files with arbitrary names.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/a714c00de3590b01. Report an issue: GitHub.

Appendix: source

Thrown at core/cas-server-core-services-registry/src/main/java/org/apereo/cas/services/resource/AbstractResourceBasedServiceRegistry.java:288

        if (!file.exists()) {
            LOGGER.warn("[{}] is not found at the path specified", fileName);
            return new ArrayList<>();
        }
        if (file.length() == 0) {
            LOGGER.debug("[{}] appears to be empty so no service definition will be loaded", fileName);
            return new ArrayList<>();
        }
        if (!fileName.isEmpty() && fileName.charAt(0) == '.') {
            LOGGER.debug("[{}] starts with ., ignoring", fileName);
            return new ArrayList<>();
        }
        if (Arrays.stream(getExtensions()).noneMatch(fileName::endsWith)) {
            LOGGER.debug("[{}] doesn't end with valid extension, ignoring", fileName);
            return new ArrayList<>();
        }

        if (!RegexUtils.matches(this.serviceFileNamePattern, fileName)) {
            LOGGER.warn("[{}] does not match the recommended pattern [{}]. "
                    + "While CAS tries to be forgiving as much as possible, it's recommended "
                    + "that you rename the file to match the requested pattern to avoid issues with duplicate service loading. "
                    + "Future CAS versions may try to strictly force the naming syntax, refusing to load the file.",
                fileName, this.serviceFileNamePattern.pattern());
        }

        LOGGER.debug("Attempting to read and parse [{}]", file.getAbsoluteFile());
        try (val in = Files.newBufferedReader(file.toPath())) {
            return registeredServiceSerializers
                .stream()
                .filter(serializer -> serializer.supports(file))
                .map(serializer -> serializer.load(in))
                .filter(Objects::nonNull)
                .flatMap(Collection::stream)
                .filter(service -> StringUtils.isNotBlank(service.getServiceId()) && StringUtils.isNotBlank(service.getName()))
                .map(this::invokeServiceRegistryListenerPostLoad)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

View on GitHub (pinned to e7288fc434)