jenkinsci/jenkins · critical · IOException

Jenkins is unable to create {pm.rootDir} Perhaps its securit

Error message

Jenkins is unable to create {pm.rootDir}
Perhaps its security privilege is insufficient

What it means

Thrown by listPluginFiles when pm.rootDir.listFiles() returns null, meaning the plugin root directory does not exist or is not a directory (or the JVM lacks read/execute permission on it). Jenkins calls this during startup initialization to enumerate installed .jpl/.hpl/.jpi/.hpi plugin files. The phrase 'unable to create' is misleading — listFiles returning null indicates the directory cannot be *listed*, not created.

Source

Thrown at core/src/main/java/hudson/init/InitStrategy.java:66

        // the ordering makes sure that during the debugging we get proper precedence among duplicates.
        // for example, while doing "mvn jpi:run" or "mvn hpi:run" on a plugin that's bundled with Jenkins, we want to the
        // *.jpl file to override the bundled jpi/hpi file.
        getBundledPluginsFromProperty(r);

        // similarly, we prefer *.jpi over *.hpi
        listPluginFiles(pm, ".jpl", r); // linked plugin. for debugging.
        listPluginFiles(pm, ".hpl", r); // linked plugin. for debugging. (for backward compatibility)
        listPluginFiles(pm, ".jpi", r); // plugin jar file
        listPluginFiles(pm, ".hpi", r); // plugin jar file (for backward compatibility)

        return r;
    }

    private void listPluginFiles(PluginManager pm, String extension, Collection<File> all) throws IOException {
        File[] files = pm.rootDir.listFiles(new FilterByExtension(extension));
        if (files == null)
            throw new IOException("Jenkins is unable to create " + pm.rootDir + "\nPerhaps its security privilege is insufficient");

        List<File> pluginFiles = new ArrayList<>();
        pluginFiles.addAll(List.of(files));
        pluginFiles.sort(Comparator.comparing(File::getName));

        all.addAll(pluginFiles);
    }

    /**
     * Lists up additional bundled plugins from the system property {@code hudson.bundled.plugins}.
     * Since 1.480 glob syntax is supported.
     * For use in {@code mvn jetty:run}.
     * TODO: maven-hpi-plugin should inject its own InitStrategy instead of having this in the core.
     */
    protected void getBundledPluginsFromProperty(final List<File> r) {
        String hplProperty = SystemProperties.getString("hudson.bundled.plugins");
        if (hplProperty != null) {
            List<File> pluginFiles = new ArrayList<>();

View on GitHub (pinned to 2e228ff40b)

Solutions

  1. Verify the JENKINS_HOME/plugins directory exists and is a real directory: ls -ld $JENKINS_HOME/plugins
  2. Ensure the OS user running Jenkins owns or can read+execute the plugins directory: chown or chmod 755 $JENKINS_HOME/plugins
  3. Check for broken symlinks inside the plugins directory and remove or fix them
  4. If running in a container, confirm the volume mount for JENKINS_HOME is correct and not read-only

Example fix

// before: directory missing causes listFiles() == null
// after: ensure dir exists before Jenkins starts
File pluginsDir = new File(jenkinsHome, "plugins");
if (!pluginsDir.isDirectory() && !pluginsDir.mkdirs()) {
    throw new IOException("Cannot create or read plugins dir: " + pluginsDir);
}
Defensive patterns

Strategy: validation

Validate before calling

File pluginsDir = new File(System.getenv("JENKINS_HOME"), "plugins");
if (!pluginsDir.isDirectory()) {
    throw new IllegalStateException("JENKINS_HOME/plugins is not a readable directory: " + pluginsDir);
}
if (pluginsDir.listFiles() == null) {
    throw new IllegalStateException("Cannot list plugins dir (permissions?): " + pluginsDir);
}

Try / catch

try {
    // init that triggers listPluginFiles
} catch (IOException e) {
    if (e.getMessage().contains("unable to create")) {
        // surface a clear filesystem/permission diagnostic to the operator
        LOGGER.log(Level.SEVERE, "Plugin directory not accessible: check JENKINS_HOME and file permissions", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Called during Jenkins init via listPluginFiles(pm, extension, all) for each of .jpl/.hpl/.jpi/.hpi. The FilterByExtension filter is passed to File.listFiles; null return triggers the IOException.

Common situations: JENKINS_HOME/plugins directory missing, on a read-only filesystem, permission mismatch between the user owning JENKINS_HOME and the user running the JVM (e.g. running as a different user than the one that owns the directory), symlink to a non-existent target, or the plugins dir being a regular file instead of a directory.

Related errors


AI-assisted analysis of jenkinsci/jenkins@2e228ff40b (2026-08-14). Data as JSON: /api/errors/40d1cffeaf4a4a1b. Report an issue: GitHub.