flowable/flowable-engine · error · FlowableException

The channel json key detection value was not found for the…

Error message

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

What it means

Thrown when a JSON inbound channel HAS a ChannelEventKeyDetection, but none of the four supported sources (fixedValue, jsonField, jsonPointerExpression, delegateExpression) is populated. The key-detection block exists but is effectively empty, so no InboundEventKeyDetector can be built.

Solutions

  1. Populate exactly one of keyDetection.fixedValue, keyDetection.jsonField, keyDetection.jsonPointerExpression, or keyDetection.delegateExpression.
  2. For nested JSON keys prefer setJsonPointerExpression("/event/type").
  3. If reusing a custom detector, set setDelegateExpression("${myKeyDetector}") to an InboundEventKeyDetector<JsonNode> bean.
  4. Validate the channel model JSON against the Flowable channel schema to ensure attribute names match (e.g. 'jsonField' not 'field').

Example fix

// before
ChannelEventKeyDetection keyDetection = new ChannelEventKeyDetection(); // empty — no field set
channelModel.setChannelEventKeyDetection(keyDetection);

// after
ChannelEventKeyDetection keyDetection = new ChannelEventKeyDetection();
keyDetection.setJsonPointerExpression("/event/type");
channelModel.setChannelEventKeyDetection(keyDetection);
Defensive patterns

Strategy: validation

Validate before calling

ChannelEventKeyDetection kd = channelModel.getChannelEventKeyDetection();
if (kd != null && isBlank(kd.getFixedValue()) && isBlank(kd.getJsonField())
        && isBlank(kd.getJsonPointerExpression()) && isBlank(kd.getDelegateExpression())) {
    throw new IllegalArgumentException("Empty keyDetection on channel " + channelModel.getKey());
}

Type guard

null

Try / catch

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

Prevention

When it happens

Trigger: Registering a JSON inbound channel where channelEventKeyDetection is non-null but all of getFixedValue, getJsonField, getJsonPointerExpression and getDelegateExpression return null/empty strings.

Common situations: XML/JSON channel model containing an empty <keyDetection/> element; setting a property name that does not exist (e.g. xpathField on a JSON channel); deserialization dropping the configured values due to wrong attribute names.

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

Appendix: source

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

        InboundEventKeyDetector<JsonNode> eventKeyDetector;
        ChannelEventKeyDetection keyDetection = channelModel.getChannelEventKeyDetection();

        if (keyDetection == null) {
            throw new FlowableException("A channel key detection value is required for inbound channel " + channelModel.getKey());
        }

        if (StringUtils.isNotEmpty(keyDetection.getFixedValue())) {
            eventKeyDetector = new InboundEventStaticKeyDetector<>(keyDetection.getFixedValue());
        } else if (StringUtils.isNotEmpty(keyDetection.getJsonField())) {
            eventKeyDetector = new JsonFieldBasedInboundEventKeyDetector(keyDetection.getJsonField());
        } else if (StringUtils.isNotEmpty(keyDetection.getJsonPointerExpression())) {
            eventKeyDetector = new JsonPointerBasedInboundEventKeyDetector(keyDetection.getJsonPointerExpression(), objectMapper);
        } else if (StringUtils.isNotEmpty(keyDetection.getDelegateExpression())) {
            //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.");
            }

View on GitHub (pinned to d6d39ce1c6)