flowable/flowable-engine · critical · ActivitiException

There are process definitions with key = ' ' and version =…

Error message

There are <n> process definitions with key = '<processDefinitionKey>' and version = '<processDefinitionVersion>'.

What it means

findProcessDefinitionByKeyAndVersion expects exactly one process definition matching key and version. If the query returns more than one row the data is inconsistent (a unique key+version pair was violated), and the engine throws ActivitiException rather than guessing which definition to use.

Solutions

  1. Find duplicates: SELECT KEY_, VERSION_, COUNT(*) FROM ACT_RE_PROCDEF GROUP BY KEY_, VERSION_ HAVING COUNT(*) > 1; delete/archive the extra rows keeping one correct definition.
  2. Never insert process-definition rows manually — deploy via the RepositoryService/deployment API so the engine assigns versions.
  3. Verify deployed definitions with repositoryService.createProcessDefinitionQuery().processDefinitionKey(k).list() to spot duplicates early.
  4. Use processDefinitionKey + latest-version query (or processDefinitionId) instead of key+version when duplicates may exist.
Defensive patterns

Strategy: fallback

Validate before calling

List<ProcessDefinition> defs = repositoryService.createProcessDefinitionQuery()
    .processDefinitionKey(key).processDefinitionVersion(version).list();
if (defs.size() > 1) throw new IllegalStateException("duplicate definitions for key=" + key);
if (defs.isEmpty()) return null;

Try / catch

try {
    def = repo.getProcessDefinitionByKeyAndVersion(key, version);
} catch (ActivitiException e) {
    // fall back to latest version for the key
    def = repositoryService.createProcessDefinitionQuery().processDefinitionKey(key)
        .latestVersion().singleResult();
}

Prevention

When it happens

Trigger: Querying with a key+version that matches multiple rows in ACT_RE_PROCDEF — normally impossible, but seen after manual DB inserts, restored backups, botched upgrades, or custom deployment code bypassing uniqueness.

Common situations: Database restores that re-imported the same definition rows; manual SQL fixes on ACT_RE_PROCDEF; custom deployment tooling inserting definitions without the engine's uniqueness handling; upgrade scripts partially applied leaving duplicate rows.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/persistence/entity/ProcessDefinitionEntityManager.java:97

    }

    public ProcessDefinitionEntity findProcessDefinitionByDeploymentAndKeyAndTenantId(String deploymentId, String processDefinitionKey, String tenantId) {
        Map<String, Object> parameters = new HashMap<>();
        parameters.put("deploymentId", deploymentId);
        parameters.put("processDefinitionKey", processDefinitionKey);
        parameters.put("tenantId", tenantId);
        return (ProcessDefinitionEntity) getDbSqlSession().selectOne("selectProcessDefinitionByDeploymentAndKeyAndTenantId", parameters);
    }

    public ProcessDefinition findProcessDefinitionByKeyAndVersion(String processDefinitionKey, Integer processDefinitionVersion) {
        ProcessDefinitionQueryImpl processDefinitionQuery = new ProcessDefinitionQueryImpl()
                .processDefinitionKey(processDefinitionKey)
                .processDefinitionVersion(processDefinitionVersion);
        List<ProcessDefinition> results = findProcessDefinitionsByQueryCriteria(processDefinitionQuery, null);
        if (results.size() == 1) {
            return results.get(0);
        } else if (results.size() > 1) {
            throw new ActivitiException("There are " + results.size() + " process definitions with key = '" + processDefinitionKey + "' and version = '" + processDefinitionVersion + "'.");
        }
        return null;
    }

    public List<ProcessDefinition> findProcessDefinitionsStartableByUser(String user) {
        return new ProcessDefinitionQueryImpl().startableByUser(user).list();
    }

    @SuppressWarnings("unchecked")
    public List<ProcessDefinition> findProcessDefinitionsByNativeQuery(Map<String, Object> parameterMap, int firstResult, int maxResults) {
        return getDbSqlSession().selectListWithRawParameter("selectProcessDefinitionByNativeQuery", parameterMap, firstResult, maxResults);
    }

    public long findProcessDefinitionCountByNativeQuery(Map<String, Object> parameterMap) {
        return (Long) getDbSqlSession().selectOne("selectProcessDefinitionCountByNativeQuery", parameterMap);
    }

    public void updateProcessDefinitionTenantIdForDeployment(String deploymentId, String newTenantId) {

View on GitHub (pinned to d6d39ce1c6)