flowable/flowable-engine · error · FlowableException

The channel expression tenant detection value was not found

Error message

The channel expression tenant detection value was not found for the channel model with key ${channelModel.key}. One of fixedValue, jsonField, jsonPointerExpression, xmlXPathExpression, delegateExpression should be set.

What it means

Analogous to key detection, inbound channels may declare how the tenant id is extracted from an event via ChannelEventTenantIdDetection. If such a detection object is present but none of fixedValue, jsonField, jsonPointerExpression, xmlXPathExpression, or delegateExpression is populated, Flowable cannot build an InboundEventTenantDetector and throws this error in createExpressionEventProcessingPipeline.

Source

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

            eventKeyDetector = new XpathBasedInboundEventKeyDetector(keyDetection.getXmlXPathExpression());
        } else {
            throw new FlowableException(
                "The channel expression key detection value was not found for the channel model with key " + channelModel.getKey()
                    + ". One of fixedValue, jsonField, jsonPointerExpression, xmlXPathExpression, delegateExpression should be set.");
        }

        ChannelEventTenantIdDetection channelEventTenantIdDetection = channelModel.getChannelEventTenantIdDetection();
        if (channelEventTenantIdDetection != null) {
            if (StringUtils.isNotEmpty(channelEventTenantIdDetection.getDelegateExpression())) {
                eventTenantDetector = resolveExpression(channelEventTenantIdDetection.getDelegateExpression(), InboundEventTenantDetector.class);
            } else if (StringUtils.isNotEmpty(channelEventTenantIdDetection.getFixedValue())) {
                eventTenantDetector = new InboundEventStaticTenantDetector<>(channelEventTenantIdDetection.getFixedValue());
            } else if (StringUtils.isNotEmpty(channelEventTenantIdDetection.getJsonPointerExpression())) {
                eventTenantDetector = new JsonPointerBasedInboundEventTenantDetector(channelEventTenantIdDetection.getJsonPointerExpression());
            } else if (StringUtils.isNotEmpty(channelEventTenantIdDetection.getxPathExpression())) {
                eventTenantDetector = new XpathBasedInboundEventTenantDetector(channelEventTenantIdDetection.getxPathExpression());
            } else {
                throw new FlowableException(
                    "The channel expression tenant detection value was not found for the channel model with key " + channelModel.getKey()
                        + ". One of fixedValue, jsonField, jsonPointerExpression, xmlXPathExpression, delegateExpression should be set.");
            }
        }

        //noinspection unchecked
        return new DefaultInboundEventProcessingPipeline(eventRepositoryService, eventDeserializer, eventFilter,
            eventKeyDetector, eventTenantDetector, eventPayloadExtractor, eventTransformer, engineConfiguration);
    }

    protected <T> T resolveExpression(String expression, Class<T> type) {
        Object value = CommandContextUtil.getEventRegistryConfiguration().getExpressionManager()
            .createExpression(expression)
            .getValue(new VariableContainerWrapper(Collections.emptyMap()));

        if (type.isInstance(value)) {
            return type.cast(value);
        }

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Populate one detection property on the ChannelEventTenantIdDetection, e.g. tenantIdDetectionFixedValue("tenant-1") or tenantIdDetectionJsonField("tenantId")
  2. Remove the tenant detection entirely if tenant awareness is not needed for this channel (null detection is allowed)
  3. If no static/expressed value fits, wire a custom InboundEventTenantDetector bean via delegateExpression

Example fix

// before
ChannelEventTenantIdDetection d = new ChannelEventTenantIdDetection();
channelModel.setChannelEventTenantIdDetection(d); // all fields empty
// after
ChannelEventTenantIdDetection d = new ChannelEventTenantIdDetection();
d.setFixedValue("acme");
channelModel.setChannelEventTenantIdDetection(d);
Defensive patterns

Strategy: validation

Validate before calling

ChannelEventTenantIdDetection d = channelModel.getChannelEventTenantIdDetection();
if (d != null && (isEmpty(d.getFixedValue()) && isEmpty(d.getJsonField()) && isEmpty(d.getJsonPointerExpression()) && isEmpty(d.getxPathExpression()) && isEmpty(d.getDelegateExpression()))) {
    throw new IllegalArgumentException("Channel '" + channelModel.getKey() + "' tenant detection has no value set");
}

Prevention

When it happens

Trigger: registerChannelModel on an inbound channel where channelModel.getChannelEventTenantIdDetection() is non-null but all its detection properties are empty, falling through the if/else-if chain to the throw.

Common situations: Adding a tenantIdDetection element to channel XML but leaving the attribute empty; builder call like keyDetectionTenantId() without arguments; copy-paste of channel config where the tenant detection values were removed.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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