apache/seatunnel · critical · SchemaEvolutionException
INVALID_SCHEMA_STRUCTURE
INVALID_SCHEMA_STRUCTURE
Error message
Failed to resolve PostgreSQL RELATION schema change for ${relationId}. Continuing could make the produced row schema diverge from the source relation. What it means
PostgresRelationSchemaChangeResolver.resolve wraps any unexpected exception (while converting a Debezium RELATION message into a SeaTunnel catalog table) into a SchemaEvolutionException with code INVALID_SCHEMA_STRUCTURE. It signals that the resolver could not derive the new schema for the relation and that continuing would let the produced rows' schema diverge from the actual PostgreSQL relation.
Source
Thrown at seatunnel-connectors-v2/connector-cdc/connector-cdc-postgres/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/postgres/source/PostgresRelationSchemaChangeResolver.java:76
Table after = null;
CatalogTable before = null;
try {
after = extractTable(record);
before = findCatalogTable(after, catalogTables);
List<AlterTableColumnEvent> events = resolveAddedColumns(before, after);
if (events.isEmpty()) {
return null;
}
events.forEach(event -> event.setSourceDialectName(DatabaseIdentifier.POSTGRESQL));
AlterTableColumnsEvent result = new AlterTableColumnsEvent(before.getTableId(), events);
result.setSourceDialectName(DatabaseIdentifier.POSTGRESQL);
return result;
} catch (SchemaEvolutionException e) {
throw e;
} catch (Exception e) {
String relationId = after == null ? "unknown" : after.id().toString();
throw new SchemaEvolutionException(
SchemaEvolutionErrorCode.INVALID_SCHEMA_STRUCTURE,
"Failed to resolve PostgreSQL RELATION schema change for "
+ relationId
+ ". Continuing could make the produced row schema diverge from the source relation.",
before == null ? null : before.getTableId(),
null,
e);
}
}
private Table extractTable(SourceRecord record) {
Struct value = (Struct) record.value();
List<Struct> changes = value.getArray(HistoryRecord.Fields.TABLE_CHANGES);
if (changes == null || changes.isEmpty()) {
throw invalidRelationRecord("PostgreSQL relation record has no table change payload");
}
TableChanges tableChanges = new ConnectTableChangeSerializer().deserialize(changes, true);
return StreamSupport.stream(tableChanges.spliterator(), false)View on GitHub (pinned to cf67b549a7)
Solutions
- Inspect the wrapped cause (`getCause()`) to find the actual conversion failure (usually an unsupported type or null metadata).
- Check the table's column types and remove/alter unsupported ones (e.g. custom or unusual types) before the job consumes them.
- Restart the pipeline with a fresh replication slot so RELATION messages are re-emitted consistently, or restore from a clean snapshot.
- If the failure is persistent for schema-evolution-exempt cases, handle SchemaEvolutionException upstream per your evolution policy.
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check relation payload before resolution
if (relationChange == null || relationChange.id() == null) {
skipEvent();
} Try / catch
try {
resolver.resolve(...);
} catch (SchemaEvolutionException e) {
log.error("RELATION resolution failed for relation; cause=", e.getCause());
throw e; // do not continue with diverging schema
} Prevention
- Avoid capturing tables with exotic/custom PostgreSQL column types
- Use a fresh replication slot after WAL retention issues
- Keep PostgreSQL DDL windows outside job runtime where possible
- Enable checkpointing so schema state is consistent after restarts
When it happens
Trigger: Any exception during RELATION-event schema resolution — e.g. malformed/unsupported column type in the relation message, null `after` payload, or an internal conversion error; `before == null ? null : before.getTableId()` shows it also handles missing prior table info.
Common situations: PostgreSQL DDL introducing types the mapping layer cannot translate; corrupted or partially applied RELATION stream after a slot lsn jump; concurrent DDL during snapshot handoff.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- PostgreSQL-CDC schema evolution requires 'decoding.plugin.na
- Interrupted while dispatching PostgreSQL relation change for
- Unable to %s filtered publication %s for %s
- The DB connection is not a valid replication connection
- Failed to start replication stream at <lsn>
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/1120de8b557b0929.
Report an issue: GitHub.