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
- Set one of tenantDetection.fixedValue, tenantDetection.jsonPointerExpression, or tenantDetection.delegateExpression.
- For a single-tenant deployment you can simply remove the tenant detection block entirely instead of leaving it empty.
- For tenant id inside the JSON payload use setJsonPointerExpression("/tenant").
- 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
- Omit tenant detection entirely for single-tenant deployments rather than leaving it empty
- Use jsonPointerExpression (not jsonField) for JSON tenant detection
- Keep tenant detection configuration in reviewed, versioned channel resources
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
- The channel xml tenant detection value was not found for…
- A channel key detection value is required for inbound…
- The channel deserializer expression for the channel model…
- The channel json key detection value was not found for the…
- The channel payload extractor expression for the channel…
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)