flowable/flowable-engine · error · FlowableException

The channel json tenant detection value was not found for…

Error message

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

What it means

Thrown when a JSON inbound channel defines a ChannelEventTenantIdDetection block, but none of fixedValue, jsonPointerExpression, or delegateExpression is set. Tenant detection is optional, but once declared it must yield an InboundEventTenantDetector.

Solutions

  1. Set one of tenantDetection.fixedValue, tenantDetection.jsonPointerExpression, or tenantDetection.delegateExpression.
  2. For a single-tenant deployment you can simply remove the tenant detection block entirely instead of leaving it empty.
  3. For tenant id inside the JSON payload use setJsonPointerExpression("/tenant").
  4. For a custom detector set setDelegateExpression("${myTenantDetector}") pointing at an InboundEventTenantDetector bean.

Example fix

// before
ChannelEventTenantIdDetection tenantDetection = new ChannelEventTenantIdDetection(); // empty
channelModel.setChannelEventTenantIdDetection(tenantDetection);

// after
ChannelEventTenantIdDetection tenantDetection = new ChannelEventTenantIdDetection();
tenantDetection.setJsonPointerExpression("/tenantId");
channelModel.setChannelEventTenantIdDetection(tenantDetection);
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

null

Try / catch

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

Prevention

When it happens

Trigger: Registering a JSON inbound channel with a non-null channelEventTenantIdDetection whose fixedValue, jsonPointerExpression and delegateExpression are all empty.

Common situations: Empty <tenantIdDetection/> element copied from another channel definition; wrong attribute names in the channel JSON so values do not bind; attempting JSON-field based tenant detection (jsonField is not supported here, only JSON pointer).

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/f5b535991f64c22f. Report an issue: GitHub.

Appendix: source

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

            //noinspection unchecked
            eventKeyDetector = resolveExpression(keyDetection.getDelegateExpression(), InboundEventKeyDetector.class);
        } else {
            throw new FlowableException(
                "The channel json key detection value was not found for the channel model with key " + channelModel.getKey()
                    + ". One of fixedValue, jsonField, jsonPointerExpression or 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.getJsonPointerExpression())) {
                eventTenantDetector = new JsonPointerBasedInboundEventTenantDetector(channelEventTenantIdDetection.getJsonPointerExpression());
            } else if (StringUtils.isNotEmpty(channelEventTenantIdDetection.getDelegateExpression())) {
                //noinspection unchecked
                eventTenantDetector = resolveExpression(channelEventTenantIdDetection.getDelegateExpression(), InboundEventTenantDetector.class);
            } else {
                throw new FlowableException(
                    "The channel json tenant detection value was not found for the channel model with key " + channelModel.getKey()
                        + ". One of fixedValue, jsonPointerExpression, delegateExpression should be set.");
            }
        }

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

    protected InboundEventProcessingPipeline createXmlEventProcessingPipeline(InboundChannelModel channelModel, 
            EventRepositoryService eventRepositoryService) {
        
        InboundEventDeserializer<Document> eventDeserializer;
        if (StringUtils.isEmpty(channelModel.getDeserializerDelegateExpression())) {
            eventDeserializer = new StringToXmlDocumentDeserializer();
        } else {
            //noinspection unchecked
            eventDeserializer = resolveExpression(channelModel.getDeserializerDelegateExpression(), InboundEventDeserializer.class);

View on GitHub (pinned to d6d39ce1c6)