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
- Set eventField on recordKey to point at the event field used as key.
- Or set delegateExpression resolving to a KafkaMessageKeyProvider.
- Or set fixedValue to a constant key string.
- 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
- Set at least one of eventField, delegateExpression or fixedValue whenever a recordKey element exists
- Lint channel model files for empty elements before deployment
- Test channel deployment in a staging environment
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
- The kafka partition value was not found for the channel…
- A channel key detection value is required for inbound…
- No channel keys configured for
- partition in TopicPartition for topic
- The channel deserializer expression for the channel model…
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)