conductor-oss/conductor · error · TransientException

Failed to remove workflow definition: %s/%d

Error message

Failed to remove workflow definition: %s/%d

What it means

Thrown when a DriverException occurs during removeWorkflowDef, which issues two statements (delete the def row and delete its index entry). Either statement failing raises this TransientException. Note the two deletes are not atomic, so a failure between them can leave the index entry orphaned.

Source

Thrown at cassandra-persistence/src/main/java/com/netflix/conductor/cassandra/dao/CassandraMetadataDAO.java:266

            String errorMsg = String.format("Error fetching workflow def: %s/%d", name, version);
            LOGGER.error(errorMsg, e);
            throw new TransientException(errorMsg, e);
        }
    }

    @Override
    public void removeWorkflowDef(String name, Integer version) {
        try {
            session.execute(deleteWorkflowDefStatement.bind(name, version));
            session.execute(
                    deleteWorkflowDefIndexStatement.bind(
                            WORKFLOW_DEF_INDEX_KEY, getWorkflowDefIndexValue(name, version)));
        } catch (DriverException e) {
            Monitors.error(CLASS_NAME, "removeWorkflowDef");
            String errorMsg =
                    String.format("Failed to remove workflow definition: %s/%d", name, version);
            LOGGER.error(errorMsg, e);
            throw new TransientException(errorMsg, e);
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<WorkflowDef> getAllWorkflowDefs() {
        try {
            ResultSet resultSet =
                    session.execute(selectAllWorkflowDefsStatement.bind(WORKFLOW_DEF_INDEX_KEY));
            List<Row> rows = resultSet.all();
            if (rows.size() == 0) {
                LOGGER.info("No workflow definitions were found.");
                return Collections.EMPTY_LIST;
            }
            return rows.stream()
                    .map(
                            row -> {
                                String defNameVersion =

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Retry the remove operation - TransientException is retryable.
  2. After a successful retry, verify the index entry is also gone (getAllWorkflowDefs) to detect/clean orphaned index rows.
  3. Ensure cluster health and that the workflow_def / index tables exist.
  4. Check the wrapped DriverException to distinguish timeout vs unavailable.

Example fix

// before: single delete attempt, no recovery
metadataDAO.removeWorkflowDef(name, version);

// after: retry, then reconcile orphaned index
RetryUtils.retryOn(TransientException.class, 3, Duration.ofMillis(200),
    () -> metadataDAO.removeWorkflowDef(name, version));
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight: confirm connectivity before deleting
if (cassandraSession.isClosed()) {
    throw new IllegalStateException("Cassandra session is closed; cannot remove workflow def");
}

Try / catch

// Retry remove; reconcile orphaned index entries afterward
try {
    metadataDAO.removeWorkflowDef(name, version);
} catch (TransientException e) {
    backoffAndRetry(() -> metadataDAO.removeWorkflowDef(name, version), 3);
}

Prevention

When it happens

Trigger: session.execute(deleteWorkflowDefStatement.bind(...)) or the subsequent deleteWorkflowDefIndexStatement raises a DriverException while removing a workflow definition.

Common situations: Cluster unavailable mid-delete; partial failure leaving an orphaned index row (workflow appears gone from the def table but lingers in the version index); connection drop under load.

Related errors


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