apereo/cas · error · IllegalArgumentException

Cannot read/load from subordinate directory

Error message

Cannot read/load from subordinate directory

What it means

After validating the directory, loadSubordinates() walks it and parses each file with Jackson into OidcFederationSubordinate; any IOException while reading or walking (unreadable file, I/O error mid-walk) is rethrown as IllegalArgumentException with this message and the original cause attached.

Solutions

  1. Inspect the wrapped cause (getCause()) to identify the failing file, then fix its permissions: chmod/chown so the CAS user can read it
  2. Remove non-JSON junk (broken symlinks, sockets) from the directory
  3. Verify the filesystem is accessible from the CAS process (mount health, container volume)
  4. Note: individual JSON parse failures surface differently (UncheckedIOException via doUnchecked); this message is I/O-level

Example fix

// before
ls -l /etc/cas/oidc/subordinates
-rw------- root root acme.json   # CAS user cannot read
// after
chown cas:cas /etc/cas/oidc/subordinates/acme.json
chmod 640 /etc/cas/oidc/subordinates/acme.json
Defensive patterns

Strategy: try-catch

Validate before calling

try (var s = Files.walk(Paths.get(subordinateDirectory))) {
    s.filter(Files::isRegularFile).forEach(p -> {
        if (!Files.isReadable(p)) throw new IllegalStateException("Unreadable: " + p);
    });
} catch (IOException e) { /* provision error */ }

Try / catch

try {
    repository = new OidcFederationSubordinateRepository(...);
} catch (IllegalArgumentException e) {
    LOGGER.error("Subordinate load I/O failed", e.getCause());
}

Prevention

When it happens

Trigger: A regular file inside the directory cannot be read or a Files.walk()/readValue() I/O error occurs during repository construction at CAS startup.

Common situations: Files owned by another user with no read permission for the CAS process; broken symlink or special file inside the directory; NFS mount dropped mid-startup; truncated/locked file.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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

Appendix: source

Thrown at support/cas-server-support-oidc-federation/src/main/java/org/apereo/cas/oidc/federation/subordinate/OidcFederationSubordinateRepository.java:55

    protected void loadSubordinates(final String subordinateDirectory) {
        if (StringUtils.isNotBlank(subordinateDirectory)) {
            LOGGER.debug("Loading subordinates...");
            val dir = Paths.get(subordinateDirectory);
            if (!Files.exists(dir)) {
                throw new IllegalArgumentException("subordinate directory [%s] does not exist".formatted(subordinateDirectory));
            }
            if (!Files.isDirectory(dir)) {
                throw new IllegalArgumentException("subordinate directory [%s] is not a directory".formatted(subordinateDirectory));
            }
            try (val stream = Files.walk(dir).filter(Files::isRegularFile).filter(Files::isReadable)) {
                stream.forEach(path -> FunctionUtils.doUnchecked(_ -> {
                    val file = path.toFile();
                    LOGGER.debug("Parsing [{}]...", file);
                    val subordinate = MAPPER.readValue(file, OidcFederationSubordinate.class);
                    subordinates.put(subordinate.getEntityId(), subordinate);
                }));
            } catch (final IOException e) {
                throw new IllegalArgumentException("Cannot read/load from subordinate directory", e);
            }
            LOGGER.info("Loaded [{}] subordinates", subordinates.size());
        }
    }
}

View on GitHub (pinned to e7288fc434)