flowable/flowable-engine · error · FlowableException

There are ${count} decision tables with key = '${decisionKey

Error message

There are ${count} decision tables with key = '${decisionKey}' and version = '${decisionVersion}'.

What it means

Flowable's DMN engine found more than one row in ACT_DMN_DECISION with the same key and version when looking up a decision table via findDecisionByKeyAndVersion. The (KEY_, VERSION_) pair is expected to identify at most one deployed decision definition; duplicates indicate corrupted or manually duplicated deployment data. The engine throws FlowableException instead of guessing which definition to use.

Source

Thrown at modules/flowable-dmn-engine/src/main/java/org/flowable/dmn/engine/impl/persistence/entity/data/impl/MybatisDecisionDataManager.java:120

    @Override
    public DecisionEntity findDecisionByDeploymentAndKeyAndTenantId(String deploymentId, String decisionKey, String tenantId) {
        Map<String, Object> parameters = new HashMap<>();
        parameters.put("deploymentId", deploymentId);
        parameters.put("decisionKey", decisionKey);
        parameters.put("tenantId", tenantId);
        return (DecisionEntity) getDbSqlSession().selectOne("selectDecisionByDeploymentAndKeyAndTenantId", parameters);
    }

    @Override
    public DecisionEntity findDecisionByKeyAndVersion(String decisionKey, Integer decisionVersion) {
        Map<String, Object> params = new HashMap<>();
        params.put("decisionKey", decisionKey);
        params.put("decisionVersion", decisionVersion);
        List<DecisionEntity> results = getDbSqlSession().selectList("selectDecisionsByKeyAndVersion", params);
        if (results.size() == 1) {
            return results.get(0);
        } else if (results.size() > 1) {
            throw new FlowableException("There are " + results.size() + " decision tables with key = '" + decisionKey + "' and version = '" + decisionVersion + "'.");
        }
        return null;
    }

    @Override
    @SuppressWarnings("unchecked")
    public DecisionEntity findDecisionByKeyAndVersionAndTenantId(String decisionKey, Integer decisionVersion, String tenantId) {
        Map<String, Object> params = new HashMap<>();
        params.put("decisionKey", decisionKey);
        params.put("decisionVersion", decisionVersion);
        params.put("tenantId", tenantId);
        List<DecisionEntity> results = getDbSqlSession().selectList("selectDecisionsByKeyAndVersionAndTenantId", params);
        if (results.size() == 1) {
            return results.get(0);
        } else if (results.size() > 1) {
            throw new FlowableException("There are " + results.size() + " decisions with key = '" + decisionKey + "' and version = '" + decisionVersion + "'.");
        }
        return null;

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Query the DB and remove/merge duplicate rows: SELECT * FROM ACT_DMN_DECISION WHERE KEY_ = '<key>' AND VERSION_ = <version>; delete the stale duplicates.
  2. Redeploy the decision table cleanly: delete the duplicate deployments via the DMN repository API (DmnRepositoryService.deleteDeployment) so version management regenerates unique rows.
  3. If duplicates are across tenants, switch to findDecisionByKeyAndVersionAndTenantId or set the tenant ID on the deployment so lookups are scoped.
  4. Audit deployment scripts to ensure they do not force a fixed version or redeploy identical resources producing duplicate (key, version) rows.

Example fix

// before: lookup fails due to duplicates
DecisionEntity d = decisionEntityManager.findDecisionByKeyAndVersion("myTable", 1);

// after: scope by tenant / ensure unique version at deploy time
DmnDeployment dep = dmnRepositoryService.createDeployment()
    .tenantId("tenant-1")
    .addClasspathResource("diagrams/myTable.dmn")
    .deploy();
DecisionEntity d = decisionEntityManager.findDecisionByKeyAndVersionAndTenantId("myTable", 1, "tenant-1");
Defensive patterns

Strategy: validation

Validate before calling

List<DecisionEntity> dupes = dmnManagementService // or direct SQL
    .executeCommand(ctx -> ctx.getDbSqlSession().selectList("selectDecisionsByKeyAndVersion",
        Map.of("decisionKey", key, "decisionVersion", version)));
if (dupes == null || dupes.size() > 1) {
    throw new IllegalStateException("Duplicate DMN decisions for " + key + " v" + version + ": clean up ACT_DMN_DECISION before lookup");
}

Try / catch

try {
    DecisionEntity d = dataManager.findDecisionByKeyAndVersion(key, version);
} catch (FlowableException e) {
    if (e.getMessage().contains("There are")) {
        // run dedup/cleanup of duplicate ACT_DMN_DECISION rows, then retry
    } else { throw e; }
}

Prevention

When it happens

Trigger: Calling findDecisionByKeyAndVersion (directly or through DMN rule/decision-table resolution APIs) when the DMN_DECISION table contains 2+ rows sharing the same KEY_ and VERSION_, e.g. after deploying the same decision table XML twice without redeploying (deployments with same resource forcing same version), manual DB copies, or imported data across environments.

Common situations: Database restored/merged from two environments with the same deployments; bulk import scripts that insert decision rows directly bypassing deployment versioning; deployment duplication caused by re-running deployment scripts with a fixed version label; multi-tenant data copied without tenant scoping (this variant has no tenant filter).

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


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