spring-projects/spring-boot · error · IllegalStateException

'files' must not be null

Error message

'files' must not be null

What it means

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.

Source

Thrown at configuration-metadata/spring-boot-configuration-metadata-changelog-generator/src/main/java/org/springframework/boot/configurationmetadata/changelog/ChangelogGenerator.java:67

	}

	private static void generate(File oldDir, File newDir, File out) throws IOException {
		String oldVersionNumber = oldDir.getName();
		ConfigurationMetadataRepository oldMetadata = buildRepository(oldDir);
		String newVersionNumber = newDir.getName();
		ConfigurationMetadataRepository newMetadata = buildRepository(newDir);
		Changelog changelog = Changelog.of(oldVersionNumber, oldMetadata, newVersionNumber, newMetadata);
		try (ChangelogWriter writer = new ChangelogWriter(out)) {
			writer.write(changelog);
		}
		System.out.println("%nConfiguration metadata changelog written to '%s'".formatted(out));
	}

	static ConfigurationMetadataRepository buildRepository(File directory) {
		ConfigurationMetadataRepositoryJsonBuilder builder = ConfigurationMetadataRepositoryJsonBuilder.create();
		File[] files = directory.listFiles();
		if (files == null) {
			throw new IllegalStateException("'files' must not be null");
		}
		for (File file : files) {
			try (JarFile jarFile = new JarFile(file)) {
				JarEntry metadataEntry = jarFile.getJarEntry("META-INF/spring-configuration-metadata.json");
				if (metadataEntry != null) {
					builder.withJsonResource(jarFile.getInputStream(metadataEntry));
				}
			}
			catch (IOException ex) {
				throw new RuntimeException(ex);
			}
		}
		return builder.build();
	}

}

View on GitHub (pinned to 5b2dbdbb8b)

Solutions

  1. Verify the argument is an existing directory: `Files.isDirectory(Path.of(arg))`.
  2. Fix the path so it points to the folder containing the version's jar files.
  3. Ensure the directory is readable and mounted before invoking the generator.

Example fix

// before
$ java -cp ... ChangelogGenerator 3.2.0 3.3.0 changelog.adoc
  # '3.2.0' is not a directory -> IllegalStateException
// after
$ ls 3.2.0   # confirm it is a directory of jars
$ java -cp ... ChangelogGenerator 3.2.0/ 3.3.0/ changelog.adoc
Defensive patterns

Strategy: validation

Validate before calling

File dir = new File(args[i]);
if (!dir.isDirectory() || !dir.canRead()) {
    throw new IllegalArgumentException("Argument must be a readable directory: " + dir);
}
File[] files = dir.listFiles();
if (files == null) throw new IllegalStateException("listFiles() returned null for " + dir);

Type guard

boolean isValidMetadataDir(File f) {
    return f != null && f.isDirectory() && f.canRead() && f.listFiles() != null;
}

Try / catch

// ChangelogGenerator.main does not wrap this; if you embed buildRepository:
try { repo = ChangelogGenerator.buildRepository(dir); }
catch (IllegalStateException ex) {
    if (ex.getMessage().equals("'files' must not be null")) {
        // fix dir path and retry, or fail with a clearer message
    } else throw ex;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of spring-projects/spring-boot@5b2dbdbb8b (2026-08-04). Data as JSON: /data/errors/4c75b5126b9bd708.json. Report an issue: GitHub.