apache/seatunnel · error · UnsupportedOperationException

Received AlterTableEvent but schema_evolution_enabled=false…

Error message

Received AlterTableEvent but schema_evolution_enabled=false at this sink. Either set schema_evolution_enabled=true to handle schema changes, or set schema-changes.enabled=false at the CDC source to suppress them.

What it means

The file sink received an AlterTableEvent (schema change from an upstream CDC source) but schema evolution is not enabled in its config. The sink refuses to apply schema changes it was not configured to handle, throwing UnsupportedOperationException. This is a deliberate configuration-mismatch guard: either the sink must opt in to schema evolution, or the CDC source must stop emitting change events.

Solutions

  1. Set schema_evolution_enabled = true in the file sink config so it can apply ALTER events
  2. Or set schema-changes.enabled = false on the CDC source to suppress AlterTableEvents entirely
  3. If the pipeline truly has a fixed schema, revert the upstream ALTER so no events are emitted

Example fix

// before
sink {
  LocalFile {
    path = "/data/output"
    file_format_type = "parquet"
  }
}
// after
sink {
  LocalFile {
    path = "/data/output"
    file_format_type = "parquet"
    schema_evolution_enabled = true
  }
}
Defensive patterns

Strategy: validation

Validate before calling

// before submitting the job
if (cdcSourceUsesSchemaChanges() && !fileSinkConfig.schemaEvolutionEnabled) {
  throw new IllegalArgumentException("Enable schema_evolution_enabled=true on the file sink or set schema-changes.enabled=false on the CDC source");
}

Try / catch

try { sink.applySchemaChange(event); } catch (UnsupportedOperationException e) { log.error("Schema evolution disabled at file sink: {}", e.getMessage()); /* fix config and resubmit */ }

Prevention

When it happens

Trigger: Calling applySchemaChange(SchemaChangeEvent) on AbstractWriteStrategy while FileSinkConfig.isSchemaEvolutionEnabled() is false, which happens when a CDC source with schema-changes.enabled=true feeds a file sink without schema_evolution_enabled=true.

Common situations: Pipelines where a MySQL/PostgreSQL CDC source picks up a new column mid-run and emits AlterTableEvents; developer upgraded the CDC connector to emit schema-change events but never enabled schema evolution on the file sink.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10). Data as JSON: /api/errors/f9fa0f92bf8fff62. Report an issue: GitHub.

Appendix: source

Thrown at seatunnel-connectors-v2/connector-file/connector-file-base/src/main/java/org/apache/seatunnel/connectors/seatunnel/file/sink/writer/AbstractWriteStrategy.java:230

    }

    /**
     * set seaTunnelRowTypeInfo in writer
     *
     * @param catalogTable seaTunnelRowType
     */
    @Override
    public void setCatalogTable(CatalogTable catalogTable) {
        this.tableSchema = catalogTable.getTableSchema();
        this.seaTunnelRowType = catalogTable.getSeaTunnelRowType();
    }

    // ── Schema Evolution ──────────────────────────────────────────────────────────

    @Override
    public void applySchemaChange(SchemaChangeEvent event) throws IOException {
        if (!fileSinkConfig.isSchemaEvolutionEnabled()) {
            throw new UnsupportedOperationException(
                    "Received AlterTableEvent but schema_evolution_enabled=false at this sink. "
                            + "Either set schema_evolution_enabled=true to handle schema changes, "
                            + "or set schema-changes.enabled=false at the CDC source to suppress them.");
        }
        log.info(
                "[FileSchemaEvolution] applying {} — before: rowType={}, sinkColumns={}, indices={}",
                event.getClass().getSimpleName(),
                seaTunnelRowType,
                sinkColumnNames,
                sinkColumnsIndexInRow);

        // Step 1: flush + close all open writers; register partial files for commit.
        // Reuses the subclass finishAndCloseFile() — Parquet and ORC each close their own
        // beingWrittenWriter map entries and add to needMoveFiles there.
        // beingWrittenFile.clear() is in a finally block to guarantee it runs even if a writer
        // fails to close, so stale path entries never accumulate in the cache.
        try {
            finishAndCloseFile();

View on GitHub (pinned to cf67b549a7)