apereo/cas · error · FileNotFoundException

Resource does not exist or is unreadable

Error message

Resource does not exist or is unreadable

What it means

AbstractMetadataResolverAdapter.getResourceInputStream opens the configured SAML metadata Resource for parsing. If resource.exists() or resource.isReadable() fails, it throws a FileNotFoundException with this message before loadMetadataFromResource can build a resolver. It means the metadata file/URL is missing, wrong, or not readable by the CAS process.

Solutions

  1. Check the configured metadata resource path/URL for typos and confirm the file exists at that exact location
  2. Fix filesystem permissions so the CAS process user can read the file
  3. If it's a classpath resource, ensure the metadata file is packaged inside the overlay at that path
  4. For remote URLs, verify reachability and that the HTTP fetch produces a readable stream
  5. Restart/redeploy after restoring the metadata file; then reload the metadata resolver

Example fix

// before
cas.authn.saml-idp.metadata.location=file:/etc/cas/saml/idp-metadata.xml   // file missing
// after: place file and grant read access
cp idp-metadata.xml /etc/cas/saml/ && chmod 644 /etc/cas/saml/idp-metadata.xml
Defensive patterns

Strategy: validation

Validate before calling

// check the metadata resource before handing it to the resolver adapter
Resource res = resourceLoader.getResource(metadataLocation);
if (!res.exists()) throw new IllegalStateException("Metadata resource missing: " + metadataLocation);
if (!res.isReadable()) throw new IllegalStateException("Metadata resource unreadable: " + metadataLocation);

Prevention

When it happens

Trigger: loadMetadataFromResource -> getResourceInputStream whenever the configured metadata Resource (file path, classpath entry, or URL) does not exist, was deleted/moved, or the OS/file permissions prevent reading.

Common situations: Typo'd metadata location in the SamlRegisteredService or samlIdp properties; file exists but CAS runs as a user without read permission; classpath resource not packaged; remote metadata URL unreachable in a way Spring Resource reports as nonexistent; container image without the metadata file mounted.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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

Appendix: source

Thrown at support/cas-server-support-saml-mdui-core/src/main/java/org/apereo/cas/support/saml/mdui/AbstractMetadataResolverAdapter.java:103

        val resolvers = new ArrayList<MetadataResolver>(entries.size());
        entries.forEach(entry -> {
            val resource = entry.getKey();
            LOGGER.debug("Loading [{}]", resource.getFilename());
            resolvers.addAll(loadMetadataFromResource(entry.getValue(), resource, entityId));
        });
        FunctionUtils.doUnchecked(_ -> {
            this.metadataResolver.setId(ChainingMetadataResolver.class.getCanonicalName());
            this.metadataResolver.setResolvers(resolvers);
            LOGGER.debug("Collected metadata from [{}] resolvers(s). Initializing aggregate resolver...", resolvers.size());
            this.metadataResolver.initialize();
            LOGGER.info("Metadata aggregate initialized successfully.");
        });
    }

    protected InputStream getResourceInputStream(final Resource resource, final String entityId) throws IOException {
        LOGGER.debug("Locating metadata resource from input stream.");
        if (!resource.exists() || !resource.isReadable()) {
            throw new FileNotFoundException("Resource does not exist or is unreadable");
        }
        return resource.getInputStream();
    }

    private List<MetadataResolver> loadMetadataFromResource(final MetadataFilter metadataFilter, final Resource resource,
                                                            final String entityId) {
        LOGGER.debug("Evaluating metadata resource [{}]", resource.getFilename());
        try (val in = getResourceInputStream(resource, entityId)) {
            if (in.available() > 0) {
                LOGGER.debug("Parsing [{}]", resource.getFilename());
                val document = this.configBean.getParserPool().parse(in);
                return buildSingleMetadataResolver(metadataFilter, resource, document);
            }
            LOGGER.warn("Input stream from resource [{}] appears empty. Moving on...", resource.getFilename());
        } catch (final Exception e) {
            LoggingUtils.warn(LOGGER, "Could not retrieve input stream from resource. Moving on...", e);
        }
        return new ArrayList<>();

View on GitHub (pinned to e7288fc434)