apache/seatunnel · warning
Cannot modify column
Error message
Cannot modify column {} to non-primitive type {} What it means
This warning is logged in IcebergRecordWriter.applySchemaChange when an AlterTableModifyColumnEvent requests changing a column to a non-primitive Iceberg type (e.g. map, list, struct). The writer only supports primitive types for modify-column updates, so the schema change is silently skipped and a warning is emitted instead of failing the job.
Solutions
- Change the DDL so the modified column uses a primitive type (string, int, long, double, decimal, timestamp, etc.)
- Manually apply the complex-type schema change in Iceberg via its own API/Spark DDL before or instead of the sync
- Flatten or cast the nested data to primitive (e.g. serialize struct to JSON string) upstream of the Iceberg sink
- If support is needed, extend IcebergRecordWriter to handle non-primitive types via update().updateColumn(..., Type) rather than the primitive-only modifyColumn
Example fix
// before ALTER TABLE mytable MODIFY COLUMN payload ROW<a INT>; // after ALTER TABLE mytable MODIFY COLUMN payload STRING; -- primitive, e.g. JSON serialized
Defensive patterns
Strategy: validation
Validate before calling
Type t = SchemaUtils.toIcebergType(column.getDataType());
if (!(t instanceof Type.PrimitiveType)) {
throw new IllegalArgumentException(
"Column " + column.getName() + " must map to a primitive Iceberg type, got: " + t);
} Type guard
boolean isPrimitiveIcebergType(org.apache.seatunnel.api.table.type.SeaTunnelDataType<?> dt) {
return SchemaUtils.toIcebergType(dt) instanceof Type.PrimitiveType;
} Prevention
- Restrict schema-evolution DDL on Iceberg sinks to primitive type changes
- Flatten/cast nested structures (ROW/ARRAY/MAP) to primitives before the sink
- Test schema-change pipelines with representative DDL events before production
When it happens
Trigger: Sink receives a schema-change event stream containing AlterTableModifyColumnEvent whose Column.getDataType() converts (via SchemaUtils.toIcebergType) to a Type that is not Type.PrimitiveType — e.g. modifying a column to ARRAY/MAP/ROW type.
Common situations: Upstream DDL changes a column to a complex/nested type and the SeaTunnel job's schema-change propagation tries to mirror it in Iceberg; auto table creation evolving from a wide source schema with nested fields.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Column already exists in table . Skipping add column…
- Column already exists in table . Skipping change column…
- Column does not exist in table . Skipping drop column…
- Column ' ' in table is NOT NULL but has no DEFAULT; adding…
- DamengDB does not support modifying the TEXT type directly…
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/351c3578bf79f5ed.
Report an issue: GitHub.
Appendix: source
Thrown at seatunnel-connectors-v2/connector-iceberg/src/main/java/org/apache/seatunnel/connectors/seatunnel/iceberg/sink/writer/IcebergRecordWriter.java:127
applySchemaChange(afterRowType, columnEvent);
}
return;
} else if (event instanceof AlterTableDropColumnEvent) {
AlterTableDropColumnEvent dropColumnEvent = (AlterTableDropColumnEvent) event;
updates.deleteColumn(dropColumnEvent.getColumn());
} else if (event instanceof AlterTableAddColumnEvent) {
AlterTableAddColumnEvent addColumnEvent = (AlterTableAddColumnEvent) event;
Column column = addColumnEvent.getColumn();
Type columnType = SchemaUtils.toIcebergType(column.getDataType());
updates.addColumn(null, column.getName(), columnType);
} else if (event instanceof AlterTableModifyColumnEvent) {
AlterTableModifyColumnEvent modifyColumnEvent = (AlterTableModifyColumnEvent) event;
Column column = modifyColumnEvent.getColumn();
Type columnType = SchemaUtils.toIcebergType(column.getDataType());
if (columnType instanceof Type.PrimitiveType) {
updates.modifyColumn(column.getName(), (Type.PrimitiveType) columnType);
} else {
log.warn(
"Cannot modify column {} to non-primitive type {}",
column.getName(),
columnType);
}
} else if (event instanceof AlterTableChangeColumnEvent) {
// rename
AlterTableChangeColumnEvent changeColumnEvent = (AlterTableChangeColumnEvent) event;
changeColumn(
schema,
changeColumnEvent.getColumn(),
changeColumnEvent.getOldColumn(),
updates);
}
if (!updates.empty()) {
applySchemaUpdate(updates);
}
log.info("Apply schema change end.");
}View on GitHub (pinned to cf67b549a7)