spring-projects/spring-boot · error · RuntimeException
Failed to read main class name from '{}'
Error message
Failed to read main class name from '{}' What it means
Thrown by ResolveMainClassName.ClassNameReader.transform() when Files.readString on the main-class-name output file raises IOException, wrapped as a RuntimeException (note: the cause is not chained). It indicates the file that resolveMainClassName previously wrote could not be read back when the provider is queried lazily.
Source
Thrown at build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/ResolveMainClassName.java:184
private final String classpath;
private ClassNameReader(String classpath) {
this.classpath = classpath;
}
@Override
public String transform(RegularFile file) {
if (file.getAsFile().length() == 0) {
throw new InvalidUserDataException(
"Main class name has not been configured and it could not be resolved from classpath "
+ this.classpath);
}
Path output = file.getAsFile().toPath();
try {
return Files.readString(output);
}
catch (IOException ex) {
throw new RuntimeException("Failed to read main class name from '" + output + "'");
}
}
}
}
View on GitHub (pinned to 5b2dbdbb8b)
Solutions
- Run a clean build: ./gradlew clean bootJar to regenerate the main-class-name file.
- Ensure no external process (IDE, antivirus, another Gradle daemon) removes files under build/ during the build.
- Avoid sharing a single build directory across parallel Gradle invocations.
- If reproducible, inspect the file path in the message and check filesystem permissions/disk health.
Example fix
// shell: force regeneration of the resolveMainClassName output // ./gradlew clean resolveMainClassName bootJar
Defensive patterns
Strategy: try-catch
Validate before calling
// Ensure the resolveMainClassName output exists and is readable before consuming
val outFile = layout.buildDirectory.file("resolvedMainClassName").get().asFile
if (!outFile.exists() || outFile.length() == 0L) {
throw GradleException("resolveMainClassName output missing; run :resolveMainClassName")
}
Try / catch
try {
val mainClass = tasks.named<ResolveMainClassName>("resolveMainClassName").get().readMainClassName().get()
} catch (ex: RuntimeException) {
if (ex.message?.startsWith("Failed to read main class name from") == true) {
logger.lifecycle("Re-running resolveMainClassName to regenerate output")
tasks.named("resolveMainClassName").get().actions.forEach { /* re-trigger */ }
}
throw ex
}
Prevention
- Run ./gradlew clean when builds are interrupted to avoid stale main-class files.
- Do not let external processes delete files under build/.
- Avoid running multiple Gradle builds against a shared build directory in parallel.
When it happens
Trigger: readMainClassName() maps outputFile through ClassNameReader; at line 181 Files.readString(output) fails (file deleted mid-build, moved, permission denied, FS error), producing the RuntimeException at line 184.
Common situations: Another task or external process deleted build/ intermediate files between resolveMainClassName and the consumer task; concurrent Gradle builds sharing a build dir; antivirus/IDE file locking on Windows; running with --parallel and a cleaned build dir; stale build after an interrupted build.
Related errors
- Failed to read '{}'
- Main class name has not been configured and it could not be
- Failed to create {}
- Failed to add {} to {}
- Failed to set file mode on CopySpec
AI-assisted analysis of spring-projects/spring-boot@5b2dbdbb8b (2026-08-04).
Data as JSON: /data/errors/6d69a7fdd92c09c6.json.
Report an issue: GitHub.