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
Thrown when unregisterChannelModel tries to reflectively access a 'listenerContainers' field on the Spring RabbitListenerEndpointRegistry and the field does not exist. This indicates the endpoint registry class is not the expected RabbitMQ/Spring AMQP implementation (Spring AMQP changed internals) or a wrong bean was injected.
Solutions
- Check the spring-rabbit/spring-amqp version's RabbitListenerEndpointRegistry source for the actual field name
- Pin a spring-amqp version compatible with this Flowable module
- Verify the injected endpointRegistry bean is the standard RabbitListenerEndpointRegistry
- If the field moved, unregister endpoints via the registry's public API (getListenerContainer(id).stop(); registry.unregisterListenerContainer(id)) instead of reflection
Example fix
// before
throw new IllegalStateException("Endpoint registry " + endpointRegistry + " does not have listenerContainers field");
// after
MessageListenerContainer container = endpointRegistry.getListenerContainer(endpointId);
if (container != null) {
endpointRegistry.getListenerContainer(endpointId).stop();
}
Defensive patterns
Strategy: validation
Validate before calling
if (ReflectionUtils.findField(endpointRegistry.getClass(), "listenerContainers") == null) { use endpointRegistry.getListenerContainer(endpointId) public API instead } Type guard
boolean usesReflectiveRegistry = ReflectionUtils.findField(endpointRegistry.getClass(), "listenerContainers") != null;
Try / catch
try { unregisterChannelModel(...); } catch (IllegalStateException e) { log.warn("Falling back to public registry API"); endpointRegistry.getListenerContainer(endpointId).stop(); } Prevention
- Pin spring-amqp versions tested with your Flowable version
- Prefer public registry APIs over reflection
- Smoke-test channel unregistration after every Spring Boot upgrade
When it happens
Trigger: Calling unregisterChannelModel with an endpointRegistry bean whose class lacks a private Map 'listenerContainers' field — typically after upgrading spring-amqp to a version that renamed/changed this internal field.
Common situations: Spring AMQP / Spring Boot version upgrades changing internal registry structure; accidentally registering a custom endpoint registry implementation; classpath with mismatched spring-rabbit versions.
Understand the failure class
Background: "is deprecated and will be removed" — deprecation warnings for old API names, keywords, and options, and how to migrate before the removal release — this error's family across 29 libraries.
Related errors
- Endpoint registry does not have listenerContainers field
- ackMode in definition
- Channel definition cannot resolve as a String[] or a String…
- Could not register rabbit listener endpoint on
- Could not register rabbit listener endpoint on
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/c858d44a8b3927a6.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-event-registry-spring/src/main/java/org/flowable/eventregistry/spring/rabbit/RabbitChannelDefinitionProcessor.java:311
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 channel {} in tenant {}", channelModel.getKey(), tenantId);
}
/**
* Register a new {@link RabbitListenerEndpoint} alongside the
* {@link RabbitListenerContainerFactory} 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(RabbitListenerEndpoint endpoint, RabbitListenerContainerFactory<?> factory) {
Assert.notNull(endpoint, "Endpoint must not be null");
Assert.hasText(endpoint.getId(), "Endpoint id must be set");
Assert.state(this.endpointRegistry != null, "No RabbitListenerEndpointRegistry 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.View on GitHub (pinned to d6d39ce1c6)