{"record":{"id":"509c307561f1d565","repo":"apache/beam","slug":"could-not-set-a-field-in-the-beamrowwrapper-because-rowdata","errorCode":null,"errorMessage":"Could not set a field in the BeamRowWrapper because rowData is read-only","messagePattern":"Could not set a field in the BeamRowWrapper because rowData is read-only","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/iceberg/src/main/java/org/apache/beam/sdk/io/iceberg/BeamRowWrapper.java","lineNumber":106,"sourceCode":"\n  /**\n   * Retrieves a field value from the wrapped row, performing any necessary type conversion to match\n   * Iceberg's internal expectations (e.g., converting Timestamps to microseconds).\n   */\n  @Override\n  public <T> @Nullable T get(int pos, Class<T> javaClass) {\n    if (row == null || row.getValue(pos) == null) {\n      return null;\n    } else if (getters[pos] != null) {\n      return javaClass.cast(getters[pos].get(checkStateNotNull(row), pos));\n    }\n\n    return javaClass.cast(checkStateNotNull(row).getValue(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 BeamRowWrapper because rowData is read-only\");\n  }\n\n  private interface PositionalGetter<T> {\n    T get(Row data, int pos);\n  }\n\n  /**\n   * Factory method to create a getter that handles type-specific conversion logic.\n   *\n   * <p>Handles special cases:\n   *\n   * <ul>\n   *   <li>UUID: Converts {@code byte[]} to Iceberg's UUID representation.\n   *   <li>DateTime: Converts Beam {@code DateTime} or logical types to microsecond timestamps.\n   *   <li>Nested Rows: Recursively wraps nested structures in a new {@code BeamRowWrapper}.\n   * </ul>\n   */","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/iceberg/src/main/java/org/apache/beam/sdk/io/iceberg/BeamRowWrapper.java#L88-L124","documentation":"BeamRowWrapper implements Iceberg's StructLike for Beam Row objects, which are immutable. Its set(int,T) always throws UnsupportedOperationException because mutating a Beam Row is not possible; the wrapper is read-only by design and intended for reading field values only.","triggerScenarios":"Any code path (e.g. Iceberg writer internals, generic updaters, or schema evolution helpers) that calls StructLike.set on a row wrapped by BeamRowWrapper; using the wrapper as a mutable record buffer.","commonSituations":"Bridging Iceberg APIs that expect a writable StructLike; copying logic from GenericRecord wrappers that allow set(); passing BeamRowWrapper to writers that mutate in place.","solutions":["Build a new Beam Row with Row.withSchema(...).addValues(...).build() instead of mutating the existing one","Use a mutable StructLike implementation (e.g. Iceberg's InternalRecordWrapper or a GenericData.Record) for write paths","Copy values out of the wrapper into a builder before modification","Ensure only read accessors (get) are used with BeamRowWrapper"],"exampleFix":"// before\nwrapper.set(pos, newValue); // throws\n// after\nRow updated = Row.withSchema(schema).addValues(newValues).build();","handlingStrategy":"validation","validationCode":"if (structLike instanceof BeamRowWrapper) throw new IllegalStateException(\"BeamRowWrapper is read-only; use Row builder\");","typeGuard":"null","tryCatchPattern":"try { wrapper.set(pos, v); } catch (UnsupportedOperationException e) { row = rebuildRow(row, pos, v); }","preventionTips":["Treat Beam Row as immutable always","Use Row.withSchema builders for modifications","Use writable StructLike impls for Iceberg write paths","Audit bridging code that calls StructLike.set"],"tags":["java","iceberg","beam","immutability"],"backgroundTag":"method-not-implemented","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}