{"record":{"id":"bb55f55c0601217d","repo":"apache/iceberg","slug":"could-not-set-a-field-in-the-rowdatawrapper-becaus-bb55f5","errorCode":null,"errorMessage":"Could not set a field in the RowDataWrapper because rowData is read-only","messagePattern":"Could not set a field in the RowDataWrapper because rowData is read-only","errorType":"exception","errorClass":"java.lang.UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"flink/v2.3/flink/src/main/java/org/apache/iceberg/flink/RowDataWrapper.java","lineNumber":83,"sourceCode":"  }\n\n  @Override\n  public int size() {\n    return types.length;\n  }\n\n  @Override\n  public <T> T get(int pos, Class<T> javaClass) {\n    if (rowData.isNullAt(pos)) {\n      return null;\n    }\n\n    return javaClass.cast(getters[pos].get(rowData, pos));\n  }\n\n  @Override\n  public <T> void set(int pos, T value) {\n    throw new UnsupportedOperationException(\n        \"Could not set a field in the RowDataWrapper because rowData is read-only\");\n  }\n\n  private interface PositionalGetter<T> {\n    T get(RowData data, int pos);\n  }\n\n  private static PositionalGetter<?> buildGetter(LogicalType logicalType, Type type) {\n    switch (logicalType.getTypeRoot()) {\n      case TINYINT:\n        return (row, pos) -> (int) row.getByte(pos);\n      case SMALLINT:\n        return (row, pos) -> (int) row.getShort(pos);\n      case CHAR:\n      case VARCHAR:\n        return (row, pos) -> row.getString(pos).toString();\n\n      case BINARY:","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/flink/v2.3/flink/src/main/java/org/apache/iceberg/flink/RowDataWrapper.java#L65-L101","documentation":"RowDataWrapper wraps a Flink RowData as an Iceberg StructLike, which is a read-only view: it only supports reading fields via positional getters backed by the underlying RowData. The set(int, T) method is therefore unsupported by design and always throws this UnsupportedOperationException whenever any code attempts to mutate a position through the wrapper. It fires when a component treats the StructLike as writable (e.g., an accumulator or reusable struct in an aggregation path tries to write into it); the offending input is the mutation attempt on the wrapped read-only rowData.","triggerScenarios":"Any code path that treats the wrapper as a writable StructLike and calls set(pos, value) — e.g. generic metadata-writing or update code handed this wrapper as a StructLike row.","commonSituations":"Reusing a StructLike wrapper designed for reading scan output in a write path; framework code that assumes StructLike implementations are mutable.","solutions":["Do not call set() on RowDataWrapper; build a mutable StructLike (e.g. a new row / GenericRowData) instead.","Wrap the target in a dedicated writable StructLike implementation for the write path."],"exampleFix":"// before\nwrapper.set(0, 42L); // throws\n// after\nGenericRowData row = new GenericRowData(arity);\nrow.setField(0, 42L);","handlingStrategy":"type-guard","validationCode":"// only use wrapper for read paths\nObjects.requireNonNull(wrapper, \"wrapper\");","typeGuard":"if (structLike instanceof RowDataWrapper) { throw new IllegalStateException(\"RowDataWrapper is read-only; use a mutable StructLike for writes\"); }","tryCatchPattern":"try { wrapper.set(pos, v); } catch (UnsupportedOperationException e) { /* fall back to mutable row */ }","preventionTips":["Treat RowDataWrapper as read-only StructLike.","Use GenericRowData or a custom writable wrapper for mutation paths.","Review StructLike usage in generic utility code."],"tags":["flink","read-only","unsupported-operation"],"backgroundTag":"unsupported-operation","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}