flowable/flowable-engine · error · FlowableException

The kafka recordKey value was not found for the channel…

Error message

The kafka recordKey value was not found for the channel model with key <channelModel.getKey()>. One of fixedValue, delegateExpression or eventField should be set.

What it means

Thrown when resolving the Kafka record key provider: the recordKey element on the outbound channel model has none of fixedValue, delegateExpression or eventField set, so no key can be produced. Flowable requires at least one key source to build the KafkaMessageKeyProvider.

Solutions

  1. Set eventField on recordKey to point at the event field used as key.
  2. Or set delegateExpression resolving to a KafkaMessageKeyProvider.
  3. Or set fixedValue to a constant key string.
  4. If a null key is actually desired (Kafka round-robin partitioning), remove the recordKey element entirely or configure the model so the resolver is not invoked with an empty recordKey.

Example fix

// before
"recordKey": {}
// after
"recordKey": { "fixedValue": "order-key" }
Defensive patterns

Strategy: validation

Validate before calling

boolean recordKeyConfigured = recordKey != null &&
    (recordKey.eventField != null || recordKey.delegateExpression != null || recordKey.fixedValue != null);

Try / catch

try {
    deployChannel(channelModel);
} catch (FlowableException e) {
    if (e.getMessage() != null && e.getMessage().contains("recordKey value was not found")) {
        log.error("Channel {} missing recordKey config", channelModel.getKey(), e);
    } else { throw e; }
}

Prevention

When it happens

Trigger: Registering an outbound Kafka channel whose <recordKey> definition is present but empty, or whose attributes are all blank/null.

Common situations: Channel model XML/JSON hand-edited and the recordKey attributes removed; migration from an older event-registry schema where defaults existed.

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

Appendix: source

Thrown at modules/flowable-event-registry-spring/src/main/java/org/flowable/eventregistry/spring/kafka/KafkaChannelDefinitionProcessor.java:720

                    "The kafka partition value was not found for the channel model with key " + channelModel.getKey()
                            + ". One of eventField, delegateExpression should be set.");
        }
    }

    protected KafkaMessageKeyProvider<?> resolveKafkaMessageKeyProvider(KafkaOutboundChannelModel channelModel) {
        KafkaOutboundChannelModel.RecordKey recordKey = channelModel.getRecordKey();
        if (recordKey == null) {
            return null;
        }
        if (StringUtils.hasText(recordKey.getEventField())) {
            return new EventPayloadKafkaMessageKeyProvider(recordKey.getEventField());
        } else if (StringUtils.hasText(recordKey.getDelegateExpression())) {
            return resolveExpression(recordKey.getDelegateExpression(), KafkaMessageKeyProvider.class);
        } else if (recordKey.getFixedValue() != null) {
            String fixedValue = org.apache.commons.lang3.StringUtils.defaultIfBlank(recordKey.getFixedValue(), null);
            return ignore -> fixedValue;
        } else {
            throw new FlowableException(
                    "The kafka recordKey value was not found for the channel model with key " + channelModel.getKey()
                            + ". One of fixedValue, delegateExpression or eventField should be set.");
        }
    }

    protected <T> T resolveExpression(String expression, Class<T> type) {
        Object value = this.resolver.evaluate(expression, this.expressionContext);
        if (type.isInstance(value)) {
            return type.cast(value);
        }

        throw new FlowableException("expected expression " + expression + " to resolve to " + type + " but it did not. Resolved value is " + value);

    }

    protected Object resolveExpression(String value) {
        String resolvedValue = resolve(value);

View on GitHub (pinned to d6d39ce1c6)