{"record":{"id":"16d70f73484c029f","repo":"apereo/cas","slug":"subordinate-directory-s-does-not-exist","errorCode":null,"errorMessage":"subordinate directory [%s] does not exist","messagePattern":"subordinate directory \\[(.+?)\\] does not exist","errorType":"console","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-oidc-federation/src/main/java/org/apereo/cas/oidc/federation/subordinate/OidcFederationSubordinateRepository.java","lineNumber":42,"sourceCode":"@Slf4j\npublic class OidcFederationSubordinateRepository {\n\n    private static final ObjectMapper MAPPER = JacksonObjectMapperFactory.builder()\n        .defaultTypingEnabled(false).build().toObjectMapper();\n\n    @Getter\n    private final Map<String, OidcFederationSubordinate> subordinates = new HashMap<>();\n\n    public OidcFederationSubordinateRepository(final OidcProperties oidcProperties) {\n        loadSubordinates(oidcProperties.getFederation().getSubordinateDirectory());\n    }\n\n    protected void loadSubordinates(final String subordinateDirectory) {\n        if (StringUtils.isNotBlank(subordinateDirectory)) {\n            LOGGER.debug(\"Loading subordinates...\");\n            val dir = Paths.get(subordinateDirectory);\n            if (!Files.exists(dir)) {\n                throw new IllegalArgumentException(\"subordinate directory [%s] does not exist\".formatted(subordinateDirectory));\n            }\n            if (!Files.isDirectory(dir)) {\n                throw new IllegalArgumentException(\"subordinate directory [%s] is not a directory\".formatted(subordinateDirectory));\n            }\n            try (val stream = Files.walk(dir).filter(Files::isRegularFile).filter(Files::isReadable)) {\n                stream.forEach(path -> FunctionUtils.doUnchecked(_ -> {\n                    val file = path.toFile();\n                    LOGGER.debug(\"Parsing [{}]...\", file);\n                    val subordinate = MAPPER.readValue(file, OidcFederationSubordinate.class);\n                    subordinates.put(subordinate.getEntityId(), subordinate);\n                }));\n            } catch (final IOException e) {\n                throw new IllegalArgumentException(\"Cannot read/load from subordinate directory\", e);\n            }\n            LOGGER.info(\"Loaded [{}] subordinates\", subordinates.size());\n        }\n    }\n}","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-oidc-federation/src/main/java/org/apereo/cas/oidc/federation/subordinate/OidcFederationSubordinateRepository.java#L24-L60","documentation":"During repository initialization, loadSubordinates() validates the configured subordinate directory before scanning it for OidcFederationSubordinate JSON files. If the path is non-blank but Files.exists() reports no such path, it throws this IllegalArgumentException to fail fast with the offending path in the message.","triggerScenarios":"CAS starts with cas.oidc.federation.subordinate-directory (or equivalent bean argument) pointing to a path that does not exist on disk, e.g. a typo, an unmounted volume, or a container path not mounted into the CAS server.","commonSituations":"Docker/Kubernetes deployments where the subordinate JSON directory is not mounted or mounted at a different path; developer copied a config from another host; directory created after CAS startup with no restart; relative path resolved against an unexpected working directory.","solutions":["Create the directory at the configured path: mkdir -p <subordinateDirectory> and place subordinate JSON files in it","Correct the cas.oidc.federation subordinate-directory property to an existing absolute path","In containers, mount the directory into the container at the exact configured path and restart CAS"],"exampleFix":"// before\ncas.oidc.federation.subordinate-directory=/etc/cas/oidc/subordinates\n// directory missing -> error\n// after\n# on host\nmkdir -p /etc/cas/oidc/subordinates\n# place *.json subordinate entity files there, then restart CAS","handlingStrategy":"validation","validationCode":"val dir = Paths.get(subordinateDirectory);\nif (StringUtils.isBlank(subordinateDirectory) || !Files.exists(dir) || !Files.isDirectory(dir)) {\n    throw new IllegalStateException(\"Subordinate directory not usable: \" + subordinateDirectory);\n}","typeGuard":null,"tryCatchPattern":"try {\n    repository = new OidcFederationSubordinateRepository(oidcProperties, ...);\n} catch (IllegalArgumentException e) {\n    LOGGER.error(\"Subordinate dir missing: {}\", e.getMessage());\n}","preventionTips":["Create the directory before CAS startup and add a deployment healthcheck for it","Use absolute paths in configuration","In containers, verify volume mounts with an init/entrypoint check"],"tags":["filesystem","configuration","startup"],"backgroundTag":"directory-not-found","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}