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
After destroying the listener container, unregisterChannelModel removes the endpoint from the endpoint registry's internal 'listenerContainers' map via reflection. If that field does not exist on the registry class (ReflectionUtils.findField returns null), it throws an IllegalStateException. This is an internal-structure assumption failure, typically caused by a Spring/Flowable version change.
Solutions
- Check Spring Framework / Flowable versions for compatibility; the processor relies on the registry's 'listenerContainers' field.
- Upgrade or downgrade Flowable to a version matching your Spring version.
- If a custom registry is used, add/maintain the listenerContainers field or override the processor.
- Report/patch: replace reflection with a proper registry API if one exists in your version.
Example fix
// before: custom registry without the expected internal field
class MyEndpointRegistry { /* no listenerContainers field */ }
// after: use/extend the supported registry implementation
class MyEndpointRegistry extends DefaultJmsListenerEndpointRegistry { /* has listenerContainers */ } Defensive patterns
Strategy: validation
Validate before calling
if (ReflectionUtils.findField(endpointRegistry.getClass(), "listenerContainers") == null) {
throw new IllegalStateException("Incompatible endpoint registry implementation: " + endpointRegistry.getClass());
} Type guard
boolean isSupportedRegistry(Object registry) {
return registry instanceof org.springframework.jms.config.DefaultJmsListenerEndpointRegistry;
} Try / catch
try {
processor.unregisterChannelModel(channelModel, tenantId);
} catch (IllegalStateException e) {
log.error("Registry implementation incompatible with processor; check Spring/Flowable versions", e);
} Prevention
- Pin tested Spring Framework versions compatible with your Flowable release.
- Use the standard DefaultJmsListenerEndpointRegistry, not custom internals-dependent registries.
- Add a compatibility check when upgrading Spring.
When it happens
Trigger: Unregistering a JMS channel endpoint when the endpointRegistry object's class has no 'listenerContainers' field — e.g. a different AbstractMessageListenerContainer registry implementation or an upgraded Spring Framework that renamed/restructured the field.
Common situations: Spring Framework upgrade changing internals of the endpoint registry; Flowable running against an unsupported Spring version; custom endpoint registry implementations.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Endpoint registry does not have listenerContainers field
- Could not resolve the JmsListenerContainerFactory to use for
- ackMode in definition
- At least one of topics, topicPartitions or topicPattern…
- Builder is missing constructor (can't pass features)
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/3d95e073605fe9ec.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-event-registry-spring/src/main/java/org/flowable/eventregistry/spring/jms/JmsChannelModelProcessor.java:191
if (listenerContainer instanceof DisposableBean) {
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 JmsListenerEndpoint} alongside the
* {@link JmsListenerContainerFactory} 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(JmsListenerEndpoint endpoint, JmsListenerContainerFactory<?> factory) {
Assert.notNull(endpoint, "Endpoint must not be null");
Assert.hasText(endpoint.getId(), "Endpoint id must be set");
Assert.state(this.endpointRegistry != null, "No JmsListenerEndpointRegistry set");
// We need to start the container immediately only if the endpoint registry is already running,View on GitHub (pinned to d6d39ce1c6)