SonarSource/sonarqube · error · IOException

Directory could not be created

Error message

Directory  could not be created

What it means

In Files2.openOutputStreamOrThrowIOE, before opening a FileOutputStream for a non-existent file, the code creates the parent directory with mkdirs(). If mkdirs() fails and the parent is still not a directory, it throws an IOException "Directory <parent> could not be created", which openOutputStream then wraps in an IllegalStateException. It signals the output file's parent directory could not be created.

Source

Thrown at server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/util/Files2.java:152

   * The parent directory will be created if it does not exist.
   * The file will be created if it does not exist.
   *
   * @param file  the file to open for output, must not be {@code null}
   * @param append if {@code true}, then bytes will be added to the
   * end of the file rather than overwriting
   * @return a new {@link FileOutputStream} for the specified file
   * @throws IOException if the specified file is a directory
   * @throws IOException if the file can not be written to
   * @throws IOException if a parent directory can not be created
   */
  public FileOutputStream openOutputStreamOrThrowIOE(File file, boolean append) throws IOException {
    if (file.exists()) {
      checkOrThrowIOE(!file.isDirectory(), "File %s exists but is a directory", file);
      checkOrThrowIOE(file.canWrite(), "File %s can not be written to", file);
    } else {
      File parent = file.getParentFile();
      if (parent != null && !parent.mkdirs() && !parent.isDirectory()) {
        throw new IOException("Directory " + parent + " could not be created");
      }
    }
    return new FileOutputStream(file, append);
  }

  /**
   * Opens a {@link FileOutputStream} for the specified file, checking and
   * creating the parent directory if it does not exist.
   * <p>
   * The parent directory will be created if it does not exist.
   * The file will be created if it does not exist.
   *
   * @param file  the file to open for output, must not be {@code null}
   * @param append if {@code true}, then bytes will be added to the
   * end of the file rather than overwriting
   * @return a new {@link FileOutputStream} for the specified file
   * @throws IllegalStateException if the specified file is a directory
   * @throws IllegalStateException if the file can not be written to

View on GitHub (pinned to 184c821202)

Solutions

  1. Check that every path component of the parent is a directory, not a file, and remove any conflicting file
  2. Grant the CE process user write/execute permission on all ancestor directories
  3. Verify the configured paths (sonar.path.data / temp dirs) are valid and on a writable volume
  4. Create the parent directory manually and re-run the task

Example fix

// before
files2.openOutputStream(new File("/opt/sonar/work")); // 'work' is a regular file -> mkdirs fails
// after
File target = new File("/opt/sonar/work/out.bin");
File parent = target.getParentFile();
if (!parent.isDirectory() && !parent.mkdirs()) {
  throw new IOException("Pre-check failed for " + parent);
}
files2.openOutputStream(target);
Defensive patterns

Strategy: validation

Validate before calling

File parent = file.getParentFile();
if (parent != null && parent.exists() && !parent.isDirectory()) {
  throw new IllegalStateException("Path component is a file: " + parent);
}
if (parent != null && !parent.canWrite()) {
  throw new IllegalStateException("Parent not writable: " + parent);
}

Try / catch

try {
  FileOutputStream out = files2.openOutputStream(file, false);
} catch (IllegalStateException e) {
  LOGGER.error("Cannot create parent dir for {}: {}", file, e.getCause(), e);
}

Prevention

When it happens

Trigger: The target file does not exist, its parent directory also does not exist, and File.mkdirs() returns false without creating it — e.g. a path component is an existing file, permission denied on an ancestor, or invalid path characters.

Common situations: Configured work/temp directory path collides with an existing regular file; CE user lacks write permission on the parent; path too long or containing invalid characters; read-only volume.

Understand the failure class

Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.

Related errors


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