junit-team/junit5 · error · ExtensionConfigurationException
@TempDir field [%s] must not be declared as final.
Error message
@TempDir field [%s] must not be declared as final.
What it means
Thrown as ExtensionConfigurationException by assertNonFinalField when a field annotated with @TempDir is declared final. JUnit needs to assign the temp directory into the field after construction, so a final field would make injection impossible and is rejected during field setup.
Source
Thrown at junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TempDirectory.java:204
private Supplier<TempDirDeletionStrategy> determineDeletionStrategy(TempDir annotation) {
var strategyClass = annotation.deletionStrategy();
return strategyClass == TempDirDeletionStrategy.class //
? this.configuration.getDefaultTempDirDeletionStrategySupplier() //
: () -> ReflectionSupport.newInstance(strategyClass);
}
private TempDirFactory determineTempDirFactory(TempDir tempDir) {
Class<? extends TempDirFactory> factory = tempDir.factory();
return factory == TempDirFactory.class //
? this.configuration.getDefaultTempDirFactorySupplier().get()
: ReflectionSupport.newInstance(factory);
}
private static void assertNonFinalField(Field field) {
if (ModifierSupport.isFinal(field)) {
throw new ExtensionConfigurationException("@TempDir field [" + field + "] must not be declared as final.");
}
}
private static void assertSupportedType(String target, Class<?> type) {
if (type != Path.class && type != File.class) {
throw new ExtensionConfigurationException("Can only resolve @TempDir " + target + " of type "
+ Path.class.getName() + " or " + File.class.getName() + " but was: " + type.getName());
}
}
private Object getPathOrFile(Class<?> elementType, AnnotatedElementContext elementContext,
ExtensionContext extensionContext, TempDir tempDir) {
TempDirFactory factory = determineTempDirFactory(tempDir);
Cleanup cleanup = new Cleanup(determineCleanupMode(tempDir), determineDeletionStrategy(tempDir));
return getPathOrFile(elementType, elementContext, factory, cleanup, extensionContext);
}
private static Object getPathOrFile(Class<?> elementType, AnnotatedElementContext elementContext,View on GitHub (pinned to f070c699a0)
Solutions
- Remove the final modifier from the @TempDir field (Java) or change Kotlin val to var.
- For Kotlin, use `lateinit var` or `var` with a nullable type.
- Prefer the @TempDir parameter form on @BeforeEach/lifecycle methods if you need immutability elsewhere.
Example fix
// before @TempDir private final Path tmp; // final -> rejected // after @TempDir private Path tmp; // Kotlin // before: val tmp: Path by ... // val = final // after: @TempDir lateinit var tmp: Path // (or nullable var)
Defensive patterns
Strategy: validation
Validate before calling
for (Field f : MyTest.class.getDeclaredFields()) {
if (f.isAnnotationPresent(TempDir.class) && Modifier.isFinal(f.getModifiers())) {
throw new IllegalStateException("@TempDir field " + f + " must not be final");
}
} Prevention
- Declare @TempDir fields non-final (Java) or as var (Kotlin).
- Prefer @TempDir parameters on @BeforeEach methods when immutability matters.
- Audit Kotlin val fields annotated with @TempDir.
When it happens
Trigger: A field declared as `private final Path tmp;` or `static final File dir;` annotated with @TempDir - assertNonFinalField(field) is invoked during field/parameter resolution in TempDirectory and ModifierSupport.isFinal(field) is true.
Common situations: Kotlin val (which compiles to final) annotated with @TempDir; Java field declared final by habit; record components or migrated code that made the field final; Lombok @Value or @Final used on the field.
Related errors
- Can only resolve @TempDir %s of type java.nio.file.Path or j
- Unsupported AnnotatedElement type for @TempDir: %s
- Failed to create default temp directory
- temp directory must be a directory
- temp directory with non-default file system cannot be inject
AI-assisted analysis of junit-team/junit5@f070c699a0 (2026-08-11).
Data as JSON: /api/errors/fb38cb6d8fed0a69.
Report an issue: GitHub.