flowable/flowable-engine · error · IllegalStateException
Endpoint registry does not have listenerContainers field
Error message
Endpoint registry <endpointRegistry> does not have listenerContainers field
What it means
The processor unregisters endpoints by reflectively removing entries from the endpoint registry's 'listenerContainers' field. If that field cannot be found on the given registry class (incompatible KafkaListenerEndpointRegistry implementation), an IllegalStateException with this message is thrown. This guards against Spring Kafka versions whose internal registry layout changed.
Solutions
- Use the standard org.springframework.kafka.config.KafkaListenerEndpointRegistry that has the listenerContainers field.
- Align spring-kafka version with the version Flowable's event-registry-spring was built against (check flowable dependency management).
- Pin/downgrade spring-kafka to a compatible version if you upgraded recently.
- Override the unregister path or subclass KafkaChannelDefinitionProcessor to handle your registry implementation.
Example fix
// before
@Bean public MyCustomRegistry kafkaListenerEndpointRegistry() { ... }
// after
@Bean public KafkaListenerEndpointRegistry kafkaListenerEndpointRegistry() { return new KafkaListenerEndpointRegistry(); } Defensive patterns
Strategy: fallback
Validate before calling
Field f = ReflectionUtils.findField(registry.getClass(), "listenerContainers");
if (f == null) throw new IllegalStateException("Incompatible KafkaListenerEndpointRegistry: " + registry.getClass()); Try / catch
try {
undeploy(channelKey);
} catch (IllegalStateException e) {
if (e.getMessage() != null && e.getMessage().contains("does not have listenerContainers field")) {
log.error("Replace registry with standard KafkaListenerEndpointRegistry", e);
} else { throw e; }
} Prevention
- Use the stock org.springframework.kafka.config.KafkaListenerEndpointRegistry
- Avoid custom EndpointRegistry implementations
- Check spring-kafka version compatibility before upgrades
When it happens
Trigger: Using a KafkaListenerEndpointRegistry subclass/replacement that no longer declares a 'listenerContainers' field when a channel is undeployed.
Common situations: Major spring-kafka upgrade that renamed/restructured the registry internals; custom EndpointRegistry implementation passed in.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- At least one of topics, topicPartitions or topicPattern…
- Builder is missing constructor (can't pass features)
- Cannot access id method/field for JPA Entity
- Cannot access id method/field for JPA Entity
- Cannot create ScriptEngineFactory
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/d6764baebef1f1e1.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-event-registry-spring/src/main/java/org/flowable/eventregistry/spring/kafka/KafkaChannelDefinitionProcessor.java:790
try {
logger.debug("Destroying message listener {} for channel {} in tenant {}", listenerContainer, channelModel.getKey(), tenantId);
((DisposableBean) listenerContainer).destroy();
} catch (Exception e) {
throw new RuntimeException("Failed to destroy listener container", e);
}
}
Field listenerContainersField = ReflectionUtils.findField(endpointRegistry.getClass(), "listenerContainers");
if (listenerContainersField != null) {
listenerContainersField.setAccessible(true);
@SuppressWarnings("unchecked")
Map<String, MessageListenerContainer> listenerContainers = (Map<String, MessageListenerContainer>) ReflectionUtils
.getField(listenerContainersField, endpointRegistry);
if (listenerContainers != null) {
listenerContainers.remove(endpointId);
}
} else {
throw new IllegalStateException("Endpoint registry " + endpointRegistry + " does not have listenerContainers field");
}
logger.info("Finished unregistering endpoint {}", endpointId);
}
/**
* Register a new {@link KafkaListenerEndpoint} alongside the
* {@link KafkaListenerContainerFactory} to use to create the underlying container.
* <p>The {@code factory} may be {@code null} if the default factory has to be
* used for that endpoint.
*/
protected void registerEndpoint(KafkaListenerEndpoint endpoint, KafkaListenerContainerFactory<?> factory) {
Assert.notNull(endpoint, "Endpoint must not be null");
Assert.hasText(endpoint.getId(), "Endpoint id must be set");
Assert.state(this.endpointRegistry != null, "No KafkaListenerEndpointRegistry set");
// We need to start the container immediately only if the endpoint registry is already running,
// otherwise we should not start it and leave it to the registry to start all the containers when it starts.
// We also need to start immediately if the application context has already been refreshed.View on GitHub (pinned to d6d39ce1c6)