flowable/flowable-engine · error · FlowableObjectNotFoundException

No channel definition found for key '' for tenant identifier

Error message

No channel definition found for key '' for tenant identifier 

What it means

Thrown when resolving a channel definition by key for a specific tenantId and no deployed definition exists for that key+tenant combination. FlowableObjectNotFoundException including the tenant identifier.

Source

Thrown at modules/flowable-event-registry/src/main/java/org/flowable/eventregistry/impl/cmd/GetChannelModelCmd.java:94

                throw new FlowableObjectNotFoundException("No channel definition found for key '" + channelDefinitionKey + "'", ChannelDefinitionEntity.class);
            }

        } else if (channelDefinitionKey != null && tenantId != null && !EventRegistryEngineConfiguration.NO_TENANT_ID.equals(tenantId) && 
                        (parentDeploymentId == null || eventEngineConfiguration.isAlwaysLookupLatestDefinitionVersion())) {

            channelDefinitionEntity = channelDefinitionEntityManager.findLatestChannelDefinitionByKeyAndTenantId(channelDefinitionKey, tenantId);
            
            if (channelDefinitionEntity == null && eventEngineConfiguration.isFallbackToDefaultTenant()) {
                String defaultTenant = eventEngineConfiguration.getDefaultTenantProvider().getDefaultTenant(tenantId, ScopeTypes.EVENT_REGISTRY, channelDefinitionKey);
                if (StringUtils.isNotEmpty(defaultTenant)) {
                    channelDefinitionEntity = channelDefinitionEntityManager.findLatestChannelDefinitionByKeyAndTenantId(channelDefinitionKey, defaultTenant);
                } else {
                    channelDefinitionEntity = channelDefinitionEntityManager.findLatestChannelDefinitionByKey(channelDefinitionKey);
                }
            }

            if (channelDefinitionEntity == null) {
                throw new FlowableObjectNotFoundException("No channel definition found for key '" + channelDefinitionKey + "' for tenant identifier " + tenantId, ChannelDefinitionEntity.class);
            }

        } else if (channelDefinitionKey != null && (tenantId == null || EventRegistryEngineConfiguration.NO_TENANT_ID.equals(tenantId)) && parentDeploymentId != null) {

            List<EventDeployment> eventDeployments = deploymentManager.getDeploymentEntityManager().findDeploymentsByQueryCriteria(
                            new EventDeploymentQueryImpl().parentDeploymentId(parentDeploymentId));
            
            if (eventDeployments != null && eventDeployments.size() > 0) {
                channelDefinitionEntity = channelDefinitionEntityManager.findChannelDefinitionByDeploymentAndKey(eventDeployments.get(0).getId(), channelDefinitionKey);
            }
            
            if (channelDefinitionEntity == null) {
                channelDefinitionEntity = channelDefinitionEntityManager.findLatestChannelDefinitionByKey(channelDefinitionKey);
            }
            
            if (channelDefinitionEntity == null) {
                throw new FlowableObjectNotFoundException("No channel definition found for key '" + channelDefinitionKey +
                        "' for parent deployment id " + parentDeploymentId, ChannelDefinitionEntity.class);

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Deploy the channel definition with the same tenantId passed at lookup time (DeploymentBuilder.tenantId(...))
  2. Verify the exact tenant id string in the database matches the lookup value
  3. If the channel is tenant-agnostic, look up without a tenant or use the engine's NO_TENANT_ID value

Example fix

// before
repositoryService.createDeployment().addClasspathResource("sms-channel.xml").deploy(); // no tenant
getChannelModel("sms-channel", null, "acme"); // looks up tenant 'acme' -> not found
// after
repositoryService.createDeployment().addClasspathResource("sms-channel.xml").tenantId("acme").deploy();
getChannelModel("sms-channel", null, "acme");
Defensive patterns

Strategy: validation

Validate before calling

ChannelDefinition cd = repositoryService.createChannelDefinitionQuery()
    .channelDefinitionKey(key).latest().singleResult(); // tenant-filtered variant if available
if (cd == null) throw new IllegalStateException("channel " + key + " not deployed for tenant " + tenantId);

Try / catch

try {
    return repositoryService.getChannelModel(null, key, tenantId, null);
} catch (FlowableObjectNotFoundException e) {
    LOGGER.error("channel {} missing for tenant {}", key, tenantId);
    throw e;
}

Prevention

When it happens

Trigger: getChannelModel with channelDefinitionKey plus a non-null tenantId (not NO_TENANT_ID) where findLatestChannelDefinitionByKeyAndTenantId returns nothing — the channel was deployed without that tenant id or without tenant isolation.

Common situations: Deploying channel definitions without setting the tenant id in the deployment while the runtime lookup passes a tenant; tenant name mismatch (case/prefix); multi-tenant data not provisioned for a new tenant.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/d0a44b9985b367d5. Report an issue: GitHub.