apache/beam · error · IllegalArgumentException

Unsupported iterable type '%s' while translating row to stru

Error message

Unsupported iterable type '%s' while translating row to struct.

What it means

addIterableToStructBuilder translates Beam array (iterable) fields into Spanner array values. If the element type of the iterable has no case in the switch, this IllegalArgumentException reports the unsupported element type. Only scalar element types (INT64, FLOAT64, STRING, BOOLEAN, TIMESTAMP, DATETIME, etc.) are supported.

Source

Thrown at sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/StructUtils.java:349

        break;
      case STRING:
        structBuilder.set(column).toStringArray((Iterable<String>) ((Object) iterable));
        break;
        // TODO: implement logical date and datetime
      case DATETIME:
        if (iterable == null) {
          structBuilder.set(column).toTimestampArray(null);
        } else {
          structBuilder
              .set(column)
              .toTimestampArray(
                  StreamSupport.stream(iterable.spliterator(), false)
                      .map(timestamp -> Timestamp.parseTimestamp(timestamp.toString()))
                      .collect(toList()));
        }
        break;
      default:
        throw new IllegalArgumentException(
            String.format(
                "Unsupported iterable type '%s' while translating row to struct.",
                beamIterableType.getTypeName()));
    }
  }

  private static java.time.Instant fromSpannerTimestamp(Timestamp spannerTimestamp) {
    long micros = spannerTimestamp.getSeconds() * 1_000_000L + spannerTimestamp.getNanos() / 1_000L;
    return java.time.Instant.ofEpochSecond(micros / 1_000_000L, (micros % 1_000_000L) * 1_000L);
  }

  private static @Nullable Object getStructValue(Struct struct, Schema.Field field) {
    String column = field.getName();
    Type.Code typeCode = struct.getColumnType(column).getCode();
    if (struct.isNull(column)) {
      return null;
    }
    switch (typeCode) {

View on GitHub (pinned to 12126d8942)

Solutions

  1. Flatten or transform the array elements into a supported scalar type (e.g. map DECIMAL elements to STRING).
  2. Replace array-of-struct fields with JSON-encoded STRING columns.
  3. Verify the Row schema's collection element type with field.getType().getCollectionElementType() before conversion.

Example fix

// before
Schema.Field.of("prices", Schema.FieldType.array(Schema.FieldType.DECIMAL))
// after
Schema.Field.of("prices", Schema.FieldType.array(Schema.FieldType.FLOAT64))
Defensive patterns

Strategy: type-guard

Type guard

boolean isArrayElementTypeSupported(Schema.FieldType arrayType) {
  Schema.FieldType el = arrayType.getCollectionElementType();
  return el != null && switch (el.getTypeName()) {
    case INT64, FLOAT64, STRING, BOOLEAN, DATETIME -> true;
    default -> false;
  };
}

Prevention

When it happens

Trigger: Converting a Beam Row with an ARRAY field whose collection element type is unsupported (e.g. array of DECIMAL or array of ROW) into a Spanner Struct via beamRowToStruct.

Common situations: Arrays of decimals/numerics from BigQuery pipelines; nested arrays produced by earlier transforms; arrays of rows from join results.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/3910a7352fa758fc. Report an issue: GitHub.