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.

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.

Appendix: 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)