SonarSource/sonarqube · critical · IllegalStateException

Fail to create or clean-up directory %s

Error message

Fail to create or clean-up directory %s

What it means

TomcatContexts.addStaticDir serves SonarQube's static content from a filesystem directory. It first calls Fs.createOrCleanupDir (forcing directory creation/cleanup via FileUtils.forceMkdir); if that raises IOException, the directory could not be created or cleaned and an IllegalStateException wrapping it is thrown, failing server startup.

Source

Thrown at server/sonar-webserver/src/main/java/org/sonar/server/app/TomcatContexts.java:94

  }

  static String getContextPath(Props props) {
    String context = props.value(WEB_CONTEXT.getKey(), "");
    if ("/".equals(context)) {
      context = "";
    } else if (!"".equals(context) && context != null && !context.startsWith("/")) {
      throw MessageException.of(format("Value of '%s' must start with a forward slash: '%s'", WEB_CONTEXT.getKey(), context));
    }
    return context;
  }

  @VisibleForTesting
  StandardContext addStaticDir(Tomcat tomcat, String contextPath, File dir) {
    try {
      fs.createOrCleanupDir(dir);
      configureDeployErrorPages(dir, contextPath);
    } catch (IOException e) {
      throw new IllegalStateException(format("Fail to create or clean-up directory %s", dir.getAbsolutePath()), e);
    }

    return addContext(tomcat, contextPath, dir);
  }

  private static StandardContext addContext(Tomcat tomcat, String contextPath, File dir) {
    try {
      StandardContext context = (StandardContext) tomcat.addWebapp(contextPath, dir.getAbsolutePath());
      context.setClearReferencesHttpClientKeepAliveThread(false);
      context.setClearReferencesStopThreads(false);
      context.setClearReferencesStopTimerThreads(false);
      context.setClearReferencesStopTimerThreads(false);
      context.setAntiResourceLocking(false);
      context.setReloadable(false);
      context.setUseHttpOnly(true);
      context.setTldValidation(false);
      context.setXmlValidation(false);
      context.setXmlNamespaceAware(false);

View on GitHub (pinned to 184c821202)

Solutions

  1. Check permissions on the directory's parent and ensure the sonar process user can write there; chown/chmod as needed
  2. Delete any plain FILE named like the expected directory so it can be created as a directory
  3. Ensure the volume is writable and has free space (Docker: use a writable volume, not a read-only mount)

Example fix

// before
sudo -u otheruser ./sonar.sh start  # user can't write to install dir
// after
sudo chown -R sonar:sonar /opt/sonarqube && sudo -u sonar ./sonar.sh start
Defensive patterns

Strategy: validation

Validate before calling

File dir = new File(home, "web");
if (dir.exists() && !dir.isDirectory()) throw new IllegalStateException(dir + " exists and is not a directory");
if (!dir.exists() && !dir.getParentFile().canWrite()) throw new IllegalStateException("No write permission on " + dir.getParentFile());

Try / catch

try { server.start(); } catch (IllegalStateException e) { if (e.getMessage().contains("Fail to create or clean-up directory")) { log.error("Check permissions/ownership of the SonarQube install dir for the process user"); } throw e; }

Prevention

When it happens

Trigger: The static-content directory (e.g. $SONARQUBE_HOME/web) cannot be created because of insufficient filesystem permissions, a read-only volume, or because a non-directory FILE already exists at that path (cleanup fails).

Common situations: Running the SonarQube process as a user without write access to the installation directory; installing over an existing 'web' file; read-only Docker layer or mounted volume; disk full.

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/d99f18f7e60550ff. Report an issue: GitHub.