{"record":{"id":"3d95e073605fe9ec","repo":"flowable/flowable-engine","slug":"endpoint-registry-endpointregistry-does-not-have","errorCode":null,"errorMessage":"Endpoint registry <endpointRegistry> does not have listenerContainers field","messagePattern":"Endpoint registry <endpointRegistry> does not have listenerContainers field","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"modules/flowable-event-registry-spring/src/main/java/org/flowable/eventregistry/spring/jms/JmsChannelModelProcessor.java","lineNumber":191,"sourceCode":"        if (listenerContainer instanceof DisposableBean) {\n            try {\n                logger.debug(\"Destroying message listener {} for channel {} in tenant {}\", listenerContainer, channelModel.getKey(), tenantId);\n                ((DisposableBean) listenerContainer).destroy();\n            } catch (Exception e) {\n                throw new RuntimeException(\"Failed to destroy listener container\", e);\n            }\n        }\n\n        Field listenerContainersField = ReflectionUtils.findField(endpointRegistry.getClass(), \"listenerContainers\");\n        if (listenerContainersField != null) {\n            listenerContainersField.setAccessible(true);\n            @SuppressWarnings(\"unchecked\")\n            Map<String, MessageListenerContainer> listenerContainers = (Map<String, MessageListenerContainer>) ReflectionUtils.getField(listenerContainersField, endpointRegistry);\n            if (listenerContainers != null) {\n                listenerContainers.remove(endpointId);\n            }\n        } else {\n            throw new IllegalStateException(\"Endpoint registry \" + endpointRegistry + \" does not have listenerContainers field\");\n        }\n\n        logger.info(\"Finished unregistering channel {} in tenant {}\", channelModel.getKey(), tenantId);\n    }\n\n    /**\n     * Register a new {@link JmsListenerEndpoint} alongside the\n     * {@link JmsListenerContainerFactory} to use to create the underlying container.\n     * <p>The {@code factory} may be {@code null} if the default factory has to be\n     * used for that endpoint.\n     */\n    protected void registerEndpoint(JmsListenerEndpoint endpoint, JmsListenerContainerFactory<?> factory) {\n        Assert.notNull(endpoint, \"Endpoint must not be null\");\n        Assert.hasText(endpoint.getId(), \"Endpoint id must be set\");\n\n        Assert.state(this.endpointRegistry != null, \"No JmsListenerEndpointRegistry set\");\n\n        // We need to start the container immediately only if the endpoint registry is already running,","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-event-registry-spring/src/main/java/org/flowable/eventregistry/spring/jms/JmsChannelModelProcessor.java#L173-L209","documentation":"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.","triggerScenarios":"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.","commonSituations":"Spring Framework upgrade changing internals of the endpoint registry; Flowable running against an unsupported Spring version; custom endpoint registry implementations.","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."],"exampleFix":"// before: custom registry without the expected internal field\nclass MyEndpointRegistry { /* no listenerContainers field */ }\n\n// after: use/extend the supported registry implementation\nclass MyEndpointRegistry extends DefaultJmsListenerEndpointRegistry { /* has listenerContainers */ }","handlingStrategy":"validation","validationCode":"if (ReflectionUtils.findField(endpointRegistry.getClass(), \"listenerContainers\") == null) {\n    throw new IllegalStateException(\"Incompatible endpoint registry implementation: \" + endpointRegistry.getClass());\n}","typeGuard":"boolean isSupportedRegistry(Object registry) {\n    return registry instanceof org.springframework.jms.config.DefaultJmsListenerEndpointRegistry;\n}","tryCatchPattern":"try {\n    processor.unregisterChannelModel(channelModel, tenantId);\n} catch (IllegalStateException e) {\n    log.error(\"Registry implementation incompatible with processor; check Spring/Flowable versions\", e);\n}","preventionTips":["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."],"tags":["reflection","spring","version-compatibility","jms"],"backgroundTag":"internal-invariant-violation","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T11:17:12.947Z"}