SonarSource/sonarqube · critical

Property '%s' is not valid, not a directory: %s

Error message

Property '%s' is not valid, not a directory: %s

What it means

AppFileSystem validates configured SonarQube directories (data, temp, etc.) before use. ensureIsNotAFile throws this IllegalStateException when a path given via a *path* property exists but is a regular file instead of a directory, since the server needs to create/clean directories at that location.

Source

Thrown at server/sonar-main/src/main/java/org/sonar/application/AppFileSystem.java:87

  public File getTempDir() {
    return settings.getProps().nonNullValueAsFile(PATH_TEMP.getKey());
  }

  private boolean createDirectory(String propKey) throws IOException {
    File dir = settings.getProps().nonNullValueAsFile(propKey);
    if (dir.exists()) {
      ensureIsNotAFile(propKey, dir);
      return false;
    }

    forceMkdir(dir);
    ensureIsNotAFile(propKey, dir);
    return true;
  }

  private static void ensureIsNotAFile(String propKey, File dir) {
    if (!dir.isDirectory()) {
      throw new IllegalStateException(format("Property '%s' is not valid, not a directory: %s",
        propKey, dir.getAbsolutePath()));
    }
  }

  private File createOrCleanTempDirectory(String propKey) throws IOException {
    File dir = settings.getProps().nonNullValueAsFile(propKey);
    LOG.info("Cleaning or creating temp directory {}", dir.getAbsolutePath());
    if (!createDirectory(propKey)) {
      Files.walkFileTree(dir.toPath(), FOLLOW_LINKS, CleanTempDirFileVisitor.VISIT_MAX_DEPTH, new CleanTempDirFileVisitor(dir.toPath()));
    }
    return dir;
  }

  private static class CleanTempDirFileVisitor extends SimpleFileVisitor<Path> {
    private static final Path SHAREDMEMORY_FILE = Paths.get("sharedmemory");
    static final int VISIT_MAX_DEPTH = 1;

    private final Path path;

View on GitHub (pinned to 184c821202)

Solutions

  1. Inspect the property named in the message and change sonar.path.* to point to a directory (or remove it to use the default).
  2. Move or delete the offending file so the server can create the directory there.
  3. Check filesystem permissions/ownership so the sonarqube user can access the intended directory.
  4. In containers/orchestrations, fix volume mounts so a directory is mounted, not a file.

Example fix

// before (conf/sonar.properties)
sonar.path.data=/opt/sonarqube/backup.tar.gz
// after
sonar.path.data=/opt/sonarqube/data
Defensive patterns

Strategy: validation

Validate before calling

for (String key : List.of("sonar.path.data", "sonar.path.temp", "sonar.path.logs", "sonar.path.web")) {
    String v = props.get(key);
    if (v != null && new File(v).exists() && !new File(v).isDirectory()) {
        throw new IllegalStateException(key + " must be a directory, got file: " + v);
    }
}

Try / catch

try { fileSystem.createDirectory(propKey); } catch (IllegalStateException e) { log.severe(e.getMessage()); System.exit(1); }

Prevention

When it happens

Trigger: A sonar.path.* property (e.g. sonar.path.data, sonar.path.temp, sonar.path.logs) points at an existing regular file, so dir.isDirectory() is false when createDirectory() runs during server startup.

Common situations: Config mistakes where a path property was set to a file (e.g. a tarball or log file) instead of a directory; a leftover file created accidentally at the expected directory path; bind-mounting a file where a directory is expected in containers.

Related errors


AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09). Data as JSON: /api/errors/894d597a4f9c0153. Report an issue: GitHub.