{"record":{"id":"fb38cb6d8fed0a69","repo":"junit-team/junit5","slug":"tempdir-field-s-must-not-be-declared-as-final","errorCode":null,"errorMessage":"@TempDir field [%s] must not be declared as final.","messagePattern":"@TempDir field \\[(.+?)\\] must not be declared as final\\.","errorType":"exception","errorClass":"ExtensionConfigurationException","httpStatus":null,"severity":"error","filePath":"junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TempDirectory.java","lineNumber":204,"sourceCode":"\n\tprivate Supplier<TempDirDeletionStrategy> determineDeletionStrategy(TempDir annotation) {\n\t\tvar strategyClass = annotation.deletionStrategy();\n\t\treturn strategyClass == TempDirDeletionStrategy.class //\n\t\t\t\t? this.configuration.getDefaultTempDirDeletionStrategySupplier() //\n\t\t\t\t: () -> ReflectionSupport.newInstance(strategyClass);\n\t}\n\n\tprivate TempDirFactory determineTempDirFactory(TempDir tempDir) {\n\t\tClass<? extends TempDirFactory> factory = tempDir.factory();\n\n\t\treturn factory == TempDirFactory.class //\n\t\t\t\t? this.configuration.getDefaultTempDirFactorySupplier().get()\n\t\t\t\t: ReflectionSupport.newInstance(factory);\n\t}\n\n\tprivate static void assertNonFinalField(Field field) {\n\t\tif (ModifierSupport.isFinal(field)) {\n\t\t\tthrow new ExtensionConfigurationException(\"@TempDir field [\" + field + \"] must not be declared as final.\");\n\t\t}\n\t}\n\n\tprivate static void assertSupportedType(String target, Class<?> type) {\n\t\tif (type != Path.class && type != File.class) {\n\t\t\tthrow new ExtensionConfigurationException(\"Can only resolve @TempDir \" + target + \" of type \"\n\t\t\t\t\t+ Path.class.getName() + \" or \" + File.class.getName() + \" but was: \" + type.getName());\n\t\t}\n\t}\n\n\tprivate Object getPathOrFile(Class<?> elementType, AnnotatedElementContext elementContext,\n\t\t\tExtensionContext extensionContext, TempDir tempDir) {\n\t\tTempDirFactory factory = determineTempDirFactory(tempDir);\n\t\tCleanup cleanup = new Cleanup(determineCleanupMode(tempDir), determineDeletionStrategy(tempDir));\n\t\treturn getPathOrFile(elementType, elementContext, factory, cleanup, extensionContext);\n\t}\n\n\tprivate static Object getPathOrFile(Class<?> elementType, AnnotatedElementContext elementContext,","sourceCodeStart":186,"sourceCodeEnd":222,"githubUrl":"https://github.com/junit-team/junit5/blob/f070c699a08b5d8393df9afd147af5c5e90bb21b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TempDirectory.java#L186-L222","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n@TempDir\nprivate final Path tmp; // final -> rejected\n\n// after\n@TempDir\nprivate Path tmp;\n\n// Kotlin\n// before:  val tmp: Path by ...  // val = final\n// after:   @TempDir lateinit var tmp: Path  // (or nullable var)","handlingStrategy":"validation","validationCode":"for (Field f : MyTest.class.getDeclaredFields()) {\n    if (f.isAnnotationPresent(TempDir.class) && Modifier.isFinal(f.getModifiers())) {\n        throw new IllegalStateException(\"@TempDir field \" + f + \" must not be final\");\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["tempdir","extension","field-injection","final"],"backgroundTag":null,"analyzedSha":"f070c699a08b5d8393df9afd147af5c5e90bb21b","analyzedAt":"2026-08-11T20:31:00.530Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}