{"record":{"id":"496f8f319400b466","repo":"testcontainers/testcontainers-java","slug":"fieldname-does-not-implement-startable","errorCode":null,"errorMessage":"FieldName: {} does not implement Startable","messagePattern":"FieldName: (.+?) does not implement Startable","errorType":"exception","errorClass":"ExtensionConfigurationException","httpStatus":null,"severity":"error","filePath":"modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java","lineNumber":235,"sourceCode":"    private Stream<StoreAdapter> findRestartContainers(Object testInstance) {\n        return ReflectionSupport\n            .findFields(testInstance.getClass(), isRestartContainer(), HierarchyTraversalMode.TOP_DOWN)\n            .stream()\n            .map(f -> getContainerInstance(testInstance, f));\n    }\n\n    private Predicate<Field> isRestartContainer() {\n        return isContainer().and(ModifierSupport::isNotStatic);\n    }\n\n    private static Predicate<Field> isContainer() {\n        return field -> {\n            boolean isAnnotatedWithContainer = AnnotationSupport.isAnnotated(field, Container.class);\n            if (isAnnotatedWithContainer) {\n                boolean isStartable = Startable.class.isAssignableFrom(field.getType());\n\n                if (!isStartable) {\n                    throw new ExtensionConfigurationException(\n                        String.format(\"FieldName: %s does not implement Startable\", field.getName())\n                    );\n                }\n                return true;\n            }\n            return false;\n        };\n    }\n\n    private static StoreAdapter getContainerInstance(final Object testInstance, final Field field) {\n        try {\n            field.setAccessible(true);\n            Startable containerInstance = (Startable) field.get(testInstance);\n            if (containerInstance == null) {\n                throw new ExtensionConfigurationException(\"Container \" + field.getName() + \" needs to be initialized\");\n            }\n            return new StoreAdapter(field.getDeclaringClass(), field.getName(), containerInstance);\n        } catch (IllegalAccessException e) {","sourceCodeStart":217,"sourceCodeEnd":253,"githubUrl":"https://github.com/testcontainers/testcontainers-java/blob/8e549514e3f01c57d70546fbb8599d138f3903e5/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java#L217-L253","documentation":"TestcontainersExtension (the @Testcontainers/@Container JUnit 5 extension) throws this ExtensionConfigurationException when a field annotated with @Container is not assignable to Startable. Only startable resources (containers or custom Startables) may be managed by the extension.","triggerScenarios":"Annotating a field with @Container whose type does not implement Startable — e.g. a String, a config object, or a custom wrapper that forgot to extend GenericContainer/implement Startable.","commonSituations":"Custom lifecycle wrappers not implementing Startable; refactoring changed a field's type; copy-pasting @Container onto an unrelated field.","solutions":["Make the field type implement Startable (e.g. extend GenericContainer<?>)","Remove @Container from fields that are not containers/Startables","Use @Container only on GenericContainer subclasses or Startable implementations","Wrap external resources in a custom Startable implementation if lifecycle management is desired"],"exampleFix":"// before\n@Container\nprivate MyDbConfig config = new MyDbConfig();\n// after\n@Container\nprivate PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>(\"postgres:16\");","handlingStrategy":"type-guard","validationCode":"for (java.lang.reflect.Field f : testClass.getDeclaredFields()) {\n    if (f.isAnnotationPresent(Container.class)\n        && !Startable.class.isAssignableFrom(f.getType())) {\n        throw new IllegalStateException(\"@Container field \" + f.getName() + \" must implement Startable\");\n    }\n}","typeGuard":"boolean isManagedContainer(java.lang.reflect.Field f) {\n    return f.isAnnotationPresent(Container.class)\n        && Startable.class.isAssignableFrom(f.getType());\n}","tryCatchPattern":"try {\n    extension.beforeEach(ctx);\n} catch (ExtensionConfigurationException e) {\n    if (e.getMessage().contains(\"does not implement Startable\")) {\n        throw new IllegalStateException(\"Fix field type or remove @Container\", e);\n    }\n    throw e;\n}","preventionTips":["Annotate only GenericContainer/Startable fields with @Container","For custom resources, implement Startable (start()/stop()) before annotating","Run one smoke test early to catch extension config errors"],"tags":["junit","testcontainers","configuration","annotation"],"backgroundTag":"invalid-argument-value","analyzedSha":"8e549514e3f01c57d70546fbb8599d138f3903e5","analyzedAt":"2026-09-12T14:56:41.227Z","contentChangedAt":"2026-09-12T14:56:41.227Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}