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

  1. Change the DDL so the modified column uses a primitive type (string, int, long, double, decimal, timestamp, etc.)
  2. Manually apply the complex-type schema change in Iceberg via its own API/Spark DDL before or instead of the sync
  3. Flatten or cast the nested data to primitive (e.g. serialize struct to JSON string) upstream of the Iceberg sink
  4. 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

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


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)