apereo/cas · warning

Configuration file [ ] is not readable/writable or is not a…

Error message

Configuration file [{}] is not readable/writable or is not a path to a file

What it means

AddPropertiesToConfigurationCommand.add() refuses to modify a configuration file if the path exists but is a directory or is not readable and writable. This guard protects the Spring Cloud config property-editing shell command from writing to a target it cannot safely read-modify-write. The command logs a warning and aborts without adding any properties.

Solutions

  1. Pass the full path to the actual configuration file (application.properties or application.yml), not its parent directory
  2. Fix filesystem permissions so the shell user can both read and write the file (chmod/chown)
  3. Check that the path is not a read-only mount (container volume, mounted disk)
  4. If the file does not exist yet, the command creates it; ensure the parent directory is writable

Example fix

// before
cas add-properties-to-configuration --file /etc/cas/config --group cas.server --name port --value 8443
// after
cas add-properties-to-configuration --file /etc/cas/config/application.properties --group cas.server --name port --value 8443
Defensive patterns

Strategy: validation

Validate before calling

File f = new File(path);
if (f.exists() && (f.isDirectory() || !f.canRead() || !f.canWrite())) {
    throw new IllegalArgumentException("Config path must be a readable/writable file: " + path);
}

Prevention

When it happens

Trigger: Running 'cas add-properties-to-configuration --file <path>' where the file path exists but is a directory, or exists with OS permissions denying read or write access to the current user.

Common situations: Pointing --file at a directory instead of the application.properties/yml file; running the CAS shell as a user lacking write permission on the config file (e.g. file owned by root or a service account); file mounted read-only in a container.

Understand the failure class

Background: "Permission denied" / "Failed to write" file errors: why a library can't write its files to disk (EACCES, EPERM, ENOSPC) and how to fix them — this error's family across 43 libraries.

Related errors


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

Appendix: source

Thrown at support/cas-server-support-shell-core/src/main/java/org/apereo/cas/shell/commands/properties/AddPropertiesToConfigurationCommand.java:56

            defaultValue = "/etc/cas/config/cas.properties"
        )
        final String file,

        @Option(
            longName = "group",
            description = "Group/module whose associated settings should be added to the CAS configuration file"
        )
        final String group
    ) throws Exception {

        if (StringUtils.isBlank(file)) {
            LOGGER.warn("Configuration file must be specified");
            return;
        }

        val filePath = new File(file);
        if (filePath.exists() && (filePath.isDirectory() || !filePath.canRead() || !filePath.canWrite())) {
            LOGGER.warn("Configuration file [{}] is not readable/writable or is not a path to a file", filePath.getCanonicalPath());
            return;
        }

        val results = findProperties(group);
        LOGGER.info("Located [{}] properties matching [{}]", results.size(), group);

        switch (FilenameUtils.getExtension(filePath.getName()).toLowerCase(Locale.ENGLISH)) {
            case "properties" -> {
                createConfigurationFileIfNeeded(filePath);
                val props = loadPropertiesFromConfigurationFile(filePath);
                writeConfigurationPropertiesToFile(filePath, results, props);
            }
            case "yaml", "yml" -> {
                createConfigurationFileIfNeeded(filePath);
                val yamlProps = CasCoreConfigurationUtils.loadYamlProperties(new FileSystemResource(filePath));
                writeYamlConfigurationPropertiesToFile(filePath, results, yamlProps);
            }
            default -> LOGGER.warn("Configuration file format [{}] is not recognized", filePath.getCanonicalPath());

View on GitHub (pinned to e7288fc434)