{"record":{"id":"40d1cffeaf4a4a1b","repo":"jenkinsci/jenkins","slug":"jenkins-is-unable-to-create-pm-rootdir-perhaps-i","errorCode":null,"errorMessage":"Jenkins is unable to create {pm.rootDir}\nPerhaps its security privilege is insufficient","messagePattern":"Jenkins is unable to create (.+?)\nPerhaps its security privilege is insufficient","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"critical","filePath":"core/src/main/java/hudson/init/InitStrategy.java","lineNumber":66,"sourceCode":"\n        // the ordering makes sure that during the debugging we get proper precedence among duplicates.\n        // for example, while doing \"mvn jpi:run\" or \"mvn hpi:run\" on a plugin that's bundled with Jenkins, we want to the\n        // *.jpl file to override the bundled jpi/hpi file.\n        getBundledPluginsFromProperty(r);\n\n        // similarly, we prefer *.jpi over *.hpi\n        listPluginFiles(pm, \".jpl\", r); // linked plugin. for debugging.\n        listPluginFiles(pm, \".hpl\", r); // linked plugin. for debugging. (for backward compatibility)\n        listPluginFiles(pm, \".jpi\", r); // plugin jar file\n        listPluginFiles(pm, \".hpi\", r); // plugin jar file (for backward compatibility)\n\n        return r;\n    }\n\n    private void listPluginFiles(PluginManager pm, String extension, Collection<File> all) throws IOException {\n        File[] files = pm.rootDir.listFiles(new FilterByExtension(extension));\n        if (files == null)\n            throw new IOException(\"Jenkins is unable to create \" + pm.rootDir + \"\\nPerhaps its security privilege is insufficient\");\n\n        List<File> pluginFiles = new ArrayList<>();\n        pluginFiles.addAll(List.of(files));\n        pluginFiles.sort(Comparator.comparing(File::getName));\n\n        all.addAll(pluginFiles);\n    }\n\n    /**\n     * Lists up additional bundled plugins from the system property {@code hudson.bundled.plugins}.\n     * Since 1.480 glob syntax is supported.\n     * For use in {@code mvn jetty:run}.\n     * TODO: maven-hpi-plugin should inject its own InitStrategy instead of having this in the core.\n     */\n    protected void getBundledPluginsFromProperty(final List<File> r) {\n        String hplProperty = SystemProperties.getString(\"hudson.bundled.plugins\");\n        if (hplProperty != null) {\n            List<File> pluginFiles = new ArrayList<>();","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/jenkinsci/jenkins/blob/2e228ff40b14dbc8b14ffbc6edf0e4383cf744fc/core/src/main/java/hudson/init/InitStrategy.java#L48-L84","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the JENKINS_HOME/plugins directory exists and is a real directory: ls -ld $JENKINS_HOME/plugins","Ensure the OS user running Jenkins owns or can read+execute the plugins directory: chown or chmod 755 $JENKINS_HOME/plugins","Check for broken symlinks inside the plugins directory and remove or fix them","If running in a container, confirm the volume mount for JENKINS_HOME is correct and not read-only"],"exampleFix":"// before: directory missing causes listFiles() == null\n// after: ensure dir exists before Jenkins starts\nFile pluginsDir = new File(jenkinsHome, \"plugins\");\nif (!pluginsDir.isDirectory() && !pluginsDir.mkdirs()) {\n    throw new IOException(\"Cannot create or read plugins dir: \" + pluginsDir);\n}","handlingStrategy":"validation","validationCode":"File pluginsDir = new File(System.getenv(\"JENKINS_HOME\"), \"plugins\");\nif (!pluginsDir.isDirectory()) {\n    throw new IllegalStateException(\"JENKINS_HOME/plugins is not a readable directory: \" + pluginsDir);\n}\nif (pluginsDir.listFiles() == null) {\n    throw new IllegalStateException(\"Cannot list plugins dir (permissions?): \" + pluginsDir);\n}","typeGuard":null,"tryCatchPattern":"try {\n    // init that triggers listPluginFiles\n} catch (IOException e) {\n    if (e.getMessage().contains(\"unable to create\")) {\n        // surface a clear filesystem/permission diagnostic to the operator\n        LOGGER.log(Level.SEVERE, \"Plugin directory not accessible: check JENKINS_HOME and file permissions\", e);\n    }\n    throw e;\n}","preventionTips":["Run the Jenkins JVM as the same OS user that owns JENKINS_HOME","Validate JENKINS_HOME/plugins is a directory in your startup health check","In containers, mount JENKINS_HOME as a writable volume, not read-only"],"tags":["filesystem","permissions","startup","plugins","jenkins-home"],"backgroundTag":null,"analyzedSha":"2e228ff40b14dbc8b14ffbc6edf0e4383cf744fc","analyzedAt":"2026-08-14T07:07:15.274Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}