testcontainers/testcontainers-java · error · ExtensionConfigurationException

Container needs to be initialized

Error message

Container {} needs to be initialized

What it means

Thrown by the JUnit Jupiter extension when a field annotated with @Container is null at the moment the extension inspects the test instance. The extension requires every container field to be assigned before lifecycle callbacks run, because it must wrap the instance in a StoreAdapter for shared lifecycle management. It is a configuration error in the test class, not a runtime/container failure.

Solutions

  1. Initialize the container field inline at declaration (e.g. 'static final GenericContainer<?> REDIS = new GenericContainer("redis:7")')
  2. If initialization must be dynamic, do it in a static initializer block or @BeforeAll that runs before the extension callback
  3. Verify the field is not shadowed or accidentally reset to null elsewhere in the test class

Example fix

// before
@Container
static GenericContainer<?> redis;

@BeforeAll
static void init() { redis = new GenericContainer<>("redis:7"); }

// after
@Container
static GenericContainer<?> redis = new GenericContainer<>("redis:7").withExposedPorts(6379);
Defensive patterns

Strategy: validation

Validate before calling

// in test setup, before running
for (Field f : testClass.getDeclaredFields()) {
  if (f.isAnnotationPresent(Container.class)) {
    f.setAccessible(true);
    if (f.get(null /* or instance */) == null)
      throw new IllegalStateException("Field " + f.getName() + " must be initialized inline");
  }
}

Type guard

static boolean isInitialized(Object testInstance, Field f) throws IllegalAccessException {
  f.setAccessible(true);
  return f.get(testInstance) != null;
}

Prevention

When it happens

Trigger: A @Container field is declared but never initialized (stays null) when beforeEach/allCallback methods call findSharedContainers or findRestartContainers, which call getContainerInstance.

Common situations: Declaring 'static GenericContainer<?> container;' and initializing it inside a @BeforeEach method that runs after the extension reads the field; typo in initializer or conditional initialization; initialization moved to @BeforeAll but field read earlier by a parent extension.

Related errors


AI-assisted analysis of testcontainers/testcontainers-java@8e549514e3 (2026-09-12). Data as JSON: /api/errors/d77fe081f62a308e. Report an issue: GitHub.

Appendix: source

Thrown at modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/TestcontainersExtension.java:250

                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) {
            throw new ExtensionConfigurationException("Can not access container defined in field " + field.getName());
        }
    }

    /**
     * An adapter for {@link Startable} that implement {@link CloseableResource}
     * thereby letting the JUnit automatically stop containers once the current
     * {@link ExtensionContext} is closed.
     */
    private static class StoreAdapter implements CloseableResource, AutoCloseable {

        @Getter
        private String key;

        private Startable container;

View on GitHub (pinned to 8e549514e3)