conductor-oss/conductor · error · NonTransientException

Invalid row with entityKey: %s found in datastore for workfl

Error message

Invalid row with entityKey: %s found in datastore for workflow: %s

What it means

While reconstructing a Workflow from its Cassandra rows, the DAO encountered a row whose ENTITY_KEY is neither ENTITY_TYPE_WORKFLOW nor ENTITY_TYPE_TASK. It throws NonTransientException because an unknown entity type signals data corruption or an unexpected schema state that re-reading will not fix. NonTransientException is NOT retried by the framework RetryTemplate, so it surfaces immediately.

Source

Thrown at cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/dao/CassandraExecutionDAO.java:535

                        session.execute(
                                selectWorkflowWithTasksStatement.bind(
                                        workflowUUID, DEFAULT_SHARD_ID));
                List<TaskModel> tasks = new ArrayList<>();

                List<Row> rows = resultSet.all();
                if (rows.size() == 0) {
                    LOGGER.info("Workflow {} not found in datastore", workflowId);
                    return null;
                }
                for (Row row : rows) {
                    String entityKey = row.getString(ENTITY_KEY);
                    if (ENTITY_TYPE_WORKFLOW.equals(entityKey)) {
                        workflow = readValue(row.getString(PAYLOAD_KEY), WorkflowModel.class);
                    } else if (ENTITY_TYPE_TASK.equals(entityKey)) {
                        TaskModel task = readValue(row.getString(PAYLOAD_KEY), TaskModel.class);
                        tasks.add(task);
                    } else {
                        throw new NonTransientException(
                                String.format(
                                        "Invalid row with entityKey: %s found in datastore for workflow: %s",
                                        entityKey, workflowId));
                    }
                }

                if (workflow != null) {
                    recordCassandraDaoRequests("getWorkflow", "n/a", workflow.getWorkflowName());
                    tasks.sort(Comparator.comparingInt(TaskModel::getSeq));
                    workflow.setTasks(tasks);
                }
            } else {
                resultSet = session.execute(selectWorkflowStatement.bind(workflowUUID));
                workflow =
                        Optional.ofNullable(resultSet.one())
                                .map(
                                        row -> {
                                            WorkflowModel wf =

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Inspect the offending row(s) in Cassandra: SELECT entity_key, payload_key FROM <table> WHERE workflow_id = ? and identify the unexpected entityKey.
  2. Align all Conductor nodes to the same version so ENTITY_TYPE constants match what is written.
  3. Repair or delete the corrupt/unknown row so only WORKFLOW and TASK rows remain for that workflowId.
  4. If a legitimate new entity type was introduced, upgrade this DAO's read path to handle it instead of throwing.

Example fix

// before
} else {
    throw new NonTransientException(
        String.format("Invalid row with entityKey: %s ...", entityKey, workflowId));
}

// after (only if the new entity type is intentional and can be skipped/handled)
} else if (ENTITY_TYPE_NEW_ENTITY.equals(entityKey)) {
    LOGGER.warn("Skipping {} row for workflow {}", entityKey, workflowId);
} else {
    throw new NonTransientException(/* ... */);
}
Defensive patterns

Strategy: validation

Validate before calling

// Pre-validate known entity types before delegating to the read path (if you own the read)
Set<String> known = Set.of(ENTITY_TYPE_WORKFLOW, ENTITY_TYPE_TASK);
// There is no public pre-check; this is a data-integrity guard you would add in a repair job:
// SELECT entity_key FROM <table> WHERE workflow_id = ? and assert entity_key IN known.

Try / catch

try {
    Workflow w = executionDAOFacade.getWorkflow(workflowId, true);
} catch (NonTransientException e) {
    // data corruption — surface a 409/500 and trigger a row-repair investigation
    LOGGER.error("Corrupt row for workflow {}", workflowId, e);
    throw e;
}

Prevention

When it happens

Trigger: getWorkflow(workflowId) returns a partition whose rows contain an entityKey value other than the recognized workflow/task constants — e.g. a new entity type written by a newer Conductor version, a manual row insert, or a partial/failed migration.

Common situations: Rolling Conductor versions where a newer build writes a new ENTITY_TYPE_* that the running build does not recognize; direct CQL writes to the workflow table; schema drift between environments.

Related errors


AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14). Data as JSON: /api/errors/99836ba5e4168198. Report an issue: GitHub.