flowable/flowable-engine · error · FlowableException

No channel keys configured for ${planItemInstanceEntity}

Error message

No channel keys configured for ${planItemInstanceEntity}

What it means

After resolving channel keys (static attributes, expressions, or collections), a send-event plan item must end up with at least one channel key unless the event is explicitly sent on the system channel. When channelKeys is empty and sendOnSystemChannel is false, Flowable throws a FlowableException identifying the plan item.

Source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/behavior/impl/SendEventActivityBehavior.java:136

                            } else {
                                throw new FlowableIllegalArgumentException("Can only use a collection of String elements for referencing channel model key");

                            }
                        }

                    } else if (resolvedChannelKey instanceof String) {
                        String[] keys = ((String) resolvedChannelKey).split(",");
                        channelKeys.addAll(Arrays.asList(keys));

                    }
                }
            }
        }

        if (channelKeys.isEmpty()) {
            if (!sendOnSystemChannel) {
                // If the event is going to be send on the system channel then it is allowed to not define any other channels
                throw new FlowableException("No channel keys configured for " + planItemInstanceEntity);
            } else {
                return Collections.emptyList();
            }
        }

        EventRepositoryService eventRepositoryService = CommandContextUtil.getEventRegistryEngineConfiguration(commandContext).getEventRepositoryService();
        List<ChannelModel> channelModels = new ArrayList<>(channelKeys.size());
        for (String channelKey : channelKeys) {
            if (Objects.equals(CmmnEngineConfiguration.NO_TENANT_ID, planItemInstanceEntity.getTenantId())) {
                channelModels.add(eventRepositoryService.getChannelModelByKey(channelKey));
            } else {
                channelModels.add(eventRepositoryService.getChannelModelByKey(channelKey, planItemInstanceEntity.getTenantId()));
            }
        }

        return channelModels;
    }

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Configure at least one channel key on the send-event plan item in the model (channel key extension element or attribute)
  2. If the channel comes from an expression, guarantee the variable is set and non-empty before the plan item executes
  3. If intentionally using the default system channel, mark the plan item to send on the system channel so an empty key list is allowed
  4. Validate the case model at design time: every send-event task has either a channel key or the system-channel flag

Example fix

// before: event task with expression ${outgoingChannel} where variable may be empty, no system-channel flag
// after: ensure default and/or validate
caseService.setVariable(caseInstanceId, "outgoingChannel", "defaultEmailChannel");
// or in the model, allow system channel fallback when no keys are present
Defensive patterns

Strategy: validation

Validate before calling

Object ch = caseService.getVariable(caseInstanceId, "outgoingChannel");
if (ch == null || ch.toString().trim().isEmpty()) {
    throw new IllegalStateException("Send-event plan item requires a non-empty channel key or system-channel flag");
}

Try / catch

try {
    runtimeService.triggerPlanItemInstance(sendEventPlanItemId);
} catch (FlowableException e) {
    if (e.getMessage().startsWith("No channel keys configured")) {
        // set channel key variable or enable system channel, then retry
    }
}

Prevention

When it happens

Trigger: getChannelModels() finds no channel keys: no channel key extension/attribute configured, or the channel key expression evaluated to empty/null/empty collection, and the plan item is not marked to send on the system channel.

Common situations: Event task modeled without channel keys; expression referencing an unset case variable; collection variable empty at runtime; system-channel flag missing while relying on expression that returns nothing.

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