flowable/flowable-engine · error · FlowableException

The channel xml tenant detection value was not found for…

Error message

The channel xml tenant detection value was not found for the channel model with key ${channelModel.key}. One of fixedValue, xmlPathExpression (or xPathExpression), delegateExpression should be set.

What it means

Thrown when an XML inbound channel declares a ChannelEventTenantIdDetection but none of fixedValue, xmlPathExpression (or the legacy xPathExpression property), or delegateExpression is set. An empty tenant-detection block cannot produce an InboundEventTenantDetector.

Solutions

  1. Set one of tenantDetection.fixedValue, tenantDetection.xmlPathExpression (or legacy xPathExpression), or tenantDetection.delegateExpression.
  2. If multi-tenancy is not used, remove the tenant detection block instead of leaving it empty.
  3. Use an XPath such as setXmlXPathExpression("/event/@tenant") to extract the tenant from the document.
  4. Check the ChannelEventTenantIdDetection getter/setter naming (xPath vs xmlPath) used by your Flowable version and set the matching property.

Example fix

// before
ChannelEventTenantIdDetection t = new ChannelEventTenantIdDetection();
t.setJsonPointerExpression("/tenant"); // not read by the XML pipeline

// after
ChannelEventTenantIdDetection t = new ChannelEventTenantIdDetection();
t.setXmlXPathExpression("/event/@tenant");
Defensive patterns

Strategy: validation

Validate before calling

ChannelEventTenantIdDetection td = channelModel.getChannelEventTenantIdDetection();
if (td != null && isBlank(td.getFixedValue()) && isBlank(td.getXmlXPathExpression())
        && isBlank(td.getxPathExpression()) && isBlank(td.getDelegateExpression())) {
    throw new IllegalArgumentException("Empty tenantIdDetection on XML channel " + channelModel.getKey());
}

Type guard

null

Try / catch

try {
    eventRegistry.registerChannelModel(channelModel);
} catch (FlowableException e) {
    if (e.getMessage().contains("xml tenant detection value was not found")) {
        logger.error("Set fixedValue/xmlPathExpression/xPathExpression/delegateExpression on channel {}", channelModel.getKey());
    }
    throw e;
}

Prevention

When it happens

Trigger: Registering an XML inbound channel with a non-null channelEventTenantIdDetection where getFixedValue, getXmlXPathExpression/getxPathExpression and getDelegateExpression are all empty.

Common situations: Property-name confusion between xPathExpression (legacy) and xmlPathExpression — setting the wrong one leaves both empty; empty <tenantIdDetection/> element; copying a JSON tenant detection (jsonPointer) into an XML channel where it is not read.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/62dfd86e7be20948. Report an issue: GitHub.

Appendix: source

Thrown at modules/flowable-event-registry/src/main/java/org/flowable/eventregistry/impl/pipeline/InboundChannelModelProcessor.java:249

        } else {
            throw new FlowableException(
                "The channel xml key detection value was not found for the channel model with key " + channelModel.getKey()
                    + ". One of fixedValue, xmlPathExpression, delegateExpression should be set.");
        }

        ChannelEventTenantIdDetection channelEventTenantIdDetection = channelModel.getChannelEventTenantIdDetection();
        if (channelEventTenantIdDetection != null) {
            if (StringUtils.isNotEmpty(channelEventTenantIdDetection.getFixedValue())) {
                eventTenantDetector = new InboundEventStaticTenantDetector<>(channelEventTenantIdDetection.getFixedValue());
            } else if (StringUtils.isNotEmpty(channelEventTenantIdDetection.getXmlXPathExpression())) {
                eventTenantDetector = new XpathBasedInboundEventTenantDetector(channelEventTenantIdDetection.getXmlXPathExpression());
            } else if (StringUtils.isNotEmpty(channelEventTenantIdDetection.getxPathExpression())) {
                eventTenantDetector = new XpathBasedInboundEventTenantDetector(channelEventTenantIdDetection.getxPathExpression());
            } else if (StringUtils.isNotEmpty(channelEventTenantIdDetection.getDelegateExpression())) {
                //noinspection unchecked
                eventTenantDetector = resolveExpression(channelEventTenantIdDetection.getDelegateExpression(), InboundEventTenantDetector.class);
            } else {
                throw new FlowableException(
                    "The channel xml tenant detection value was not found for the channel model with key " + channelModel.getKey()
                        + ". One of fixedValue, xmlPathExpression (or xPathExpression), delegateExpression should be set.");
            }
        }

        return new DefaultInboundEventProcessingPipeline<>(eventRepositoryService, eventDeserializer, eventFilter,
            eventKeyDetector, eventTenantDetector, eventPayloadExtractor, eventTransformer, engineConfiguration);
    }

    protected <T> InboundEventPayloadExtractor<T> createInboundEventPayloadExtractor(InboundChannelModel channelModel,
            InboundEventPayloadExtractor<T> payloadExtractorProvider) {
        
        InboundEventPayloadExtractor<T> modelEventPayloadExtractor;
        if (StringUtils.isEmpty(channelModel.getPayloadExtractorDelegateExpression())) {
            modelEventPayloadExtractor = payloadExtractorProvider;
        } else {
            //noinspection unchecked
            modelEventPayloadExtractor = resolveExpression(channelModel.getPayloadExtractorDelegateExpression(), InboundEventPayloadExtractor.class);

View on GitHub (pinned to d6d39ce1c6)