{"id":"4c75b5126b9bd708","repo":"spring-projects/spring-boot","slug":"files-must-not-be-null","errorCode":null,"errorMessage":"'files' must not be null","messagePattern":"'files' must not be null","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"configuration-metadata/spring-boot-configuration-metadata-changelog-generator/src/main/java/org/springframework/boot/configurationmetadata/changelog/ChangelogGenerator.java","lineNumber":67,"sourceCode":"\t}\n\n\tprivate static void generate(File oldDir, File newDir, File out) throws IOException {\n\t\tString oldVersionNumber = oldDir.getName();\n\t\tConfigurationMetadataRepository oldMetadata = buildRepository(oldDir);\n\t\tString newVersionNumber = newDir.getName();\n\t\tConfigurationMetadataRepository newMetadata = buildRepository(newDir);\n\t\tChangelog changelog = Changelog.of(oldVersionNumber, oldMetadata, newVersionNumber, newMetadata);\n\t\ttry (ChangelogWriter writer = new ChangelogWriter(out)) {\n\t\t\twriter.write(changelog);\n\t\t}\n\t\tSystem.out.println(\"%nConfiguration metadata changelog written to '%s'\".formatted(out));\n\t}\n\n\tstatic ConfigurationMetadataRepository buildRepository(File directory) {\n\t\tConfigurationMetadataRepositoryJsonBuilder builder = ConfigurationMetadataRepositoryJsonBuilder.create();\n\t\tFile[] files = directory.listFiles();\n\t\tif (files == null) {\n\t\t\tthrow new IllegalStateException(\"'files' must not be null\");\n\t\t}\n\t\tfor (File file : files) {\n\t\t\ttry (JarFile jarFile = new JarFile(file)) {\n\t\t\t\tJarEntry metadataEntry = jarFile.getJarEntry(\"META-INF/spring-configuration-metadata.json\");\n\t\t\t\tif (metadataEntry != null) {\n\t\t\t\t\tbuilder.withJsonResource(jarFile.getInputStream(metadataEntry));\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new RuntimeException(ex);\n\t\t\t}\n\t\t}\n\t\treturn builder.build();\n\t}\n\n}\n","sourceCodeStart":49,"sourceCodeEnd":84,"githubUrl":"https://github.com/spring-projects/spring-boot/blob/5b2dbdbb8be64415eb6552f81ff7c449c8d251e6/configuration-metadata/spring-boot-configuration-metadata-changelog-generator/src/main/java/org/springframework/boot/configurationmetadata/changelog/ChangelogGenerator.java#L49-L84","documentation":"ChangelogGenerator.buildRepository calls directory.listFiles(); if it returns null (the File is not a directory or an I/O error occurred), an IllegalStateException is thrown. The generator cannot proceed without a directory of jars to scan for spring-configuration-metadata.json.","triggerScenarios":"Invoking ChangelogGenerator main with an argument that does not resolve to an existing, readable directory - e.g. the path is a file, does not exist, or is unreadable. listFiles() returns null exactly in those cases per its contract.","commonSituations":"Passing a wrong version directory path to the changelog generator; a missing/unmounted directory in CI; typo in the version number directory name; pointing at a path that is actually a jar rather than a folder of jars.","solutions":["Verify the argument is an existing directory: `Files.isDirectory(Path.of(arg))`.","Fix the path so it points to the folder containing the version's jar files.","Ensure the directory is readable and mounted before invoking the generator."],"exampleFix":"// before\n$ java -cp ... ChangelogGenerator 3.2.0 3.3.0 changelog.adoc\n  # '3.2.0' is not a directory -> IllegalStateException\n// after\n$ ls 3.2.0   # confirm it is a directory of jars\n$ java -cp ... ChangelogGenerator 3.2.0/ 3.3.0/ changelog.adoc","handlingStrategy":"validation","validationCode":"File dir = new File(args[i]);\nif (!dir.isDirectory() || !dir.canRead()) {\n    throw new IllegalArgumentException(\"Argument must be a readable directory: \" + dir);\n}\nFile[] files = dir.listFiles();\nif (files == null) throw new IllegalStateException(\"listFiles() returned null for \" + dir);","typeGuard":"boolean isValidMetadataDir(File f) {\n    return f != null && f.isDirectory() && f.canRead() && f.listFiles() != null;\n}","tryCatchPattern":"// ChangelogGenerator.main does not wrap this; if you embed buildRepository:\ntry { repo = ChangelogGenerator.buildRepository(dir); }\ncatch (IllegalStateException ex) {\n    if (ex.getMessage().equals(\"'files' must not be null\")) {\n        // fix dir path and retry, or fail with a clearer message\n    } else throw ex;\n}","preventionTips":["Validate both directory args with Files.isDirectory before calling the generator.","Ensure the directories are mounted and readable in the run environment (CI).","Use absolute paths to avoid ambiguity about the working directory."],"tags":["spring-boot","configuration-metadata","changelog","file-io","validation"],"analyzedSha":"5b2dbdbb8be64415eb6552f81ff7c449c8d251e6","analyzedAt":"2026-08-04T18:53:14.967Z","schemaVersion":2}