apereo/cas · warning
[ ] is not readable. Check file permissions
Error message
[{}] is not readable. Check file permissions What it means
During load(File), AbstractResourceBasedServiceRegistry checks file.canRead() before parsing. If the file is unreadable due to OS permissions, it logs this warning and returns an empty collection — the service definition is silently not loaded.
Solutions
- Fix file permissions so the CAS process user can read the file (chmod/chown).
- Ensure files copied or mounted into the services directory are readable by all needed users (e.g. 0644).
- Check SELinux/AppAudit policies if permissions look correct but access is still denied.
Example fix
// before -rw------- root root 1000001-example.json // after chown cas:cas 1000001-example.json && chmod 644 1000001-example.json
Defensive patterns
Strategy: validation
Validate before calling
File f = new File(path);
if (!f.canRead()) {
throw new IllegalStateException("File not readable by CAS user: " + f.getAbsolutePath());
} Prevention
- Deploy service files with 0644 permissions owned by the CAS user.
- After volume mounts or file copies, verify readability as the runtime user (sudo -u cas cat file).
- Check SELinux/AppArmor when POSIX permissions look correct.
When it happens
Trigger: Calling serviceRegistry.load(file) (directly or via directory scan/watcher) on a file the CAS process cannot read, e.g. permission bits excluding the runtime user.
Common situations: Service JSON files copied in as root with 0600 permissions; container user mismatch after volume mount; SELinux/AppArmor denials.
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
- The service definition file could not be saved at
- GraalVM native image executable is unable to discover…
- Failed to delete service definition file
- [ ] is not found at the path specified
- Unable to create folder
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/27c1e7e70deeee06.
Report an issue: GitHub.
Appendix: source
Thrown at core/cas-server-core-services-registry/src/main/java/org/apereo/cas/services/resource/AbstractResourceBasedServiceRegistry.java:267
.filter(service -> StringUtils.isNotBlank(service.getServiceId()) && StringUtils.isNotBlank(service.getName()))
.sorted()
.collect(Collectors.toMap(RegisteredService::getId, Function.identity(),
(s1, s2) -> {
BaseResourceBasedRegisteredServiceWatcher.LOG_SERVICE_DUPLICATE.accept(s2);
return s1;
}, LinkedHashMap::new));
val listedServices = new ArrayList<>(this.services.values());
val results = registeredServiceReplicationStrategy.updateLoadedRegisteredServicesFromCache(listedServices, this);
results.forEach(service -> publishEvent(new CasRegisteredServiceLoadedEvent(this, service, clientInfo)));
return results;
});
}
@Override
public Collection<RegisteredService> load(final File file) {
val fileName = file.getName();
if (!file.canRead()) {
LOGGER.warn("[{}] is not readable. Check file permissions", fileName);
return new ArrayList<>();
}
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<>();
}View on GitHub (pinned to e7288fc434)