[Bug]: Row.toString throws for an ITERABLE field that is not backed by a List
- Dominant language
- Java
- Stars
- 8.7k
- Forks
- 4.7k
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 196
Description
### What happened?
`Row#toString` throws for an `ITERABLE` field whose value is a plain `Iterable`:
```java
Schema schema =
Schema.builder().addStringField("k").addIterableField("vals", FieldType.STRING).build();
Iterable bare = () -> Arrays.asList("p", "q").iterator();
Row.withSchema(schema).attachValues("k1", bare).toString();
```
```
java.lang.IllegalArgumentException: value type is 'class ...' for field type 'ITERABLE'
at org.apache.beam.sdk.schemas.SchemaUtils.toPrettyFieldValueString(SchemaUtils.java:273)
```
`toPrettyFieldValueString` requires a `List` before iterating:
```java
if (!(value instanceof List)) {
throw new IllegalArgumentException(...);
}
```
An `ITERABLE` field declares an `Iterable`, so the guard is stricter than the type it is guarding. The branch below it only iterates and counts — both available from an `Iterable` once materialised.
`Row#toString` is `SchemaUtils.toPrettyString(this)`, so one unusual field takes out logging and debugger output for **every** field beside it, which is a poor trade for a stricter check in a renderer.
### Note on where the fix belongs
There is a reasonable position that a materialised `Row` should always hold a `List` for `ARRAY`/`ITERABLE`, and that a non-`List` arriving here means a producer is at fault. That may well be true and worth fixing separately — but the reproducer above uses only `Schema.builder`, `Row.withSchema(...).attachValues(...)` and `toString()`, so a value that is merely `Iterable` does reach the renderer through the public API, and a `toString()` that throws is hard to defend regardless of who produced the value.
### Issue Priority
Priority: 3 (minor)
### Issue Components
- [x] Component: Java SDK
Contributor guide
Research direction
Start in SchemaUtils.java at toPrettyFieldValueString and trace the call from Row#toString through SchemaUtils.toPrettyString. Run the reproducer from the issue and add regression coverage for an ITERABLE backed by a plain Iterable; done means Row#toString completes without throwing for that value.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100