testcontainers/testcontainers-java · error · ExtensionConfigurationException
FieldName: does not implement Startable
Error message
FieldName: {} does not implement Startable What it means
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.
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
Example fix
// before
@Container
private MyDbConfig config = new MyDbConfig();
// after
@Container
private PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16"); Defensive patterns
Strategy: type-guard
Validate before calling
for (java.lang.reflect.Field f : testClass.getDeclaredFields()) {
if (f.isAnnotationPresent(Container.class)
&& !Startable.class.isAssignableFrom(f.getType())) {
throw new IllegalStateException("@Container field " + f.getName() + " must implement Startable");
}
} Type guard
boolean isManagedContainer(java.lang.reflect.Field f) {
return f.isAnnotationPresent(Container.class)
&& Startable.class.isAssignableFrom(f.getType());
} Try / catch
try {
extension.beforeEach(ctx);
} catch (ExtensionConfigurationException e) {
if (e.getMessage().contains("does not implement Startable")) {
throw new IllegalStateException("Fix field type or remove @Container", e);
}
throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: Custom lifecycle wrappers not implementing Startable; refactoring changed a field's type; copy-pasting @Container onto an unrelated field.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Container needs to be initialized
- Changing startup timeout is not supported with mode
- Unexpected scheme
- Setting a in not supported in the versions below 22.1.0
- The provided service (service) has no quota to configure
AI-assisted analysis of testcontainers/testcontainers-java@8e549514e3 (2026-09-12).
Data as JSON: /api/errors/496f8f319400b466.
Report an issue: GitHub.
Appendix: source
Thrown at modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java:235
private Stream<StoreAdapter> findRestartContainers(Object testInstance) {
return ReflectionSupport
.findFields(testInstance.getClass(), isRestartContainer(), HierarchyTraversalMode.TOP_DOWN)
.stream()
.map(f -> getContainerInstance(testInstance, f));
}
private Predicate<Field> isRestartContainer() {
return isContainer().and(ModifierSupport::isNotStatic);
}
private static Predicate<Field> isContainer() {
return field -> {
boolean isAnnotatedWithContainer = AnnotationSupport.isAnnotated(field, Container.class);
if (isAnnotatedWithContainer) {
boolean isStartable = Startable.class.isAssignableFrom(field.getType());
if (!isStartable) {
throw new ExtensionConfigurationException(
String.format("FieldName: %s does not implement Startable", field.getName())
);
}
return true;
}
return false;
};
}
private static StoreAdapter getContainerInstance(final Object testInstance, final Field field) {
try {
field.setAccessible(true);
Startable containerInstance = (Startable) field.get(testInstance);
if (containerInstance == null) {
throw new ExtensionConfigurationException("Container " + field.getName() + " needs to be initialized");
}
return new StoreAdapter(field.getDeclaringClass(), field.getName(), containerInstance);
} catch (IllegalAccessException e) {View on GitHub (pinned to 8e549514e3)