{"record":{"id":"351c3578bf79f5ed","repo":"apache/seatunnel","slug":"cannot-modify-column-to-non-primitive-type","errorCode":null,"errorMessage":"Cannot modify column {} to non-primitive type {}","messagePattern":"Cannot modify column (.+?) to non-primitive type (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"seatunnel-connectors-v2/connector-iceberg/src/main/java/org/apache/seatunnel/connectors/seatunnel/iceberg/sink/writer/IcebergRecordWriter.java","lineNumber":127,"sourceCode":"                applySchemaChange(afterRowType, columnEvent);\n            }\n            return;\n        } else if (event instanceof AlterTableDropColumnEvent) {\n            AlterTableDropColumnEvent dropColumnEvent = (AlterTableDropColumnEvent) event;\n            updates.deleteColumn(dropColumnEvent.getColumn());\n        } else if (event instanceof AlterTableAddColumnEvent) {\n            AlterTableAddColumnEvent addColumnEvent = (AlterTableAddColumnEvent) event;\n            Column column = addColumnEvent.getColumn();\n            Type columnType = SchemaUtils.toIcebergType(column.getDataType());\n            updates.addColumn(null, column.getName(), columnType);\n        } else if (event instanceof AlterTableModifyColumnEvent) {\n            AlterTableModifyColumnEvent modifyColumnEvent = (AlterTableModifyColumnEvent) event;\n            Column column = modifyColumnEvent.getColumn();\n            Type columnType = SchemaUtils.toIcebergType(column.getDataType());\n            if (columnType instanceof Type.PrimitiveType) {\n                updates.modifyColumn(column.getName(), (Type.PrimitiveType) columnType);\n            } else {\n                log.warn(\n                        \"Cannot modify column {} to non-primitive type {}\",\n                        column.getName(),\n                        columnType);\n            }\n        } else if (event instanceof AlterTableChangeColumnEvent) {\n            // rename\n            AlterTableChangeColumnEvent changeColumnEvent = (AlterTableChangeColumnEvent) event;\n            changeColumn(\n                    schema,\n                    changeColumnEvent.getColumn(),\n                    changeColumnEvent.getOldColumn(),\n                    updates);\n        }\n        if (!updates.empty()) {\n            applySchemaUpdate(updates);\n        }\n        log.info(\"Apply schema change end.\");\n    }","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-iceberg/src/main/java/org/apache/seatunnel/connectors/seatunnel/iceberg/sink/writer/IcebergRecordWriter.java#L109-L145","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nALTER TABLE mytable MODIFY COLUMN payload ROW<a INT>;\n// after\nALTER TABLE mytable MODIFY COLUMN payload STRING; -- primitive, e.g. JSON serialized","handlingStrategy":"validation","validationCode":"Type t = SchemaUtils.toIcebergType(column.getDataType());\nif (!(t instanceof Type.PrimitiveType)) {\n    throw new IllegalArgumentException(\n        \"Column \" + column.getName() + \" must map to a primitive Iceberg type, got: \" + t);\n}","typeGuard":"boolean isPrimitiveIcebergType(org.apache.seatunnel.api.table.type.SeaTunnelDataType<?> dt) {\n    return SchemaUtils.toIcebergType(dt) instanceof Type.PrimitiveType;\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["iceberg","schema-evolution","ddl","unsupported-type"],"backgroundTag":"unsupported-operation","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}