apache/beam · error · IllegalArgumentException
The input schema must have exactly one field of type byte.
Error message
The input schema must have exactly one field of type byte.
What it means
After confirming the input schema has exactly one field, TFRecordWriteSchemaTransformProvider.expand() checks that this field's type is BYTES, because TFRecord elements must be raw byte arrays. A single field of any other type throws this IllegalArgumentException.
Source
Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/io/TFRecordWriteSchemaTransformProvider.java:146
writeTransform = writeTransform.withNumShards(configuration.getNumShards());
} else {
writeTransform = writeTransform.withoutSharding();
}
if (Boolean.TRUE.equals(configuration.getNoSpilling())) {
writeTransform = writeTransform.withNoSpilling();
}
if (configuration.getMaxNumWritersPerBundle() != null) {
writeTransform =
writeTransform.withMaxNumWritersPerBundle(configuration.getMaxNumWritersPerBundle());
}
// Obtain input schema and verify only one field and its bytes
Schema inputSchema = input.get(INPUT).getSchema();
int numFields = inputSchema.getFields().size();
if (numFields != 1) {
throw new IllegalArgumentException("Expecting exactly one field, found " + numFields);
} else if (!inputSchema.getField(0).getType().equals(Schema.FieldType.BYTES)) {
throw new IllegalArgumentException(
"The input schema must have exactly one field of type byte.");
}
final String schemaField;
if (inputSchema.getField(0).getName() != null) {
schemaField = inputSchema.getField(0).getName();
} else {
schemaField = "record";
}
PCollection<Row> inputRows = input.get(INPUT);
// Convert Beam Rows to byte arrays
SerializableFunction<Row, byte[]> rowToBytesFn = getRowToBytesFn(schemaField);
Schema errorSchema = ErrorHandling.errorSchema(inputSchema);
boolean handleErrors = ErrorHandling.hasOutput(configuration.getErrorHandling());
View on GitHub (pinned to 12126d8942)
Solutions
- Convert the field to byte[] upstream (e.g. String.getBytes(StandardCharsets.UTF_8)) so the schema field type is BYTES.
- Change the upstream MapElements/SQL cast to emit TypeDescriptor.of(byte[].class) / BYTES.
- Use a format designed for typed data (Parquet/Avro transforms) if you don't want manual serialization.
Example fix
// before PCollection<String> lines = ...; lines.apply(TFRecordWriteSchemaTransformProvider...); // field type STRING // after PCollection<byte[]> bytes = lines.apply(MapElements.into(TypeDescriptor.of(byte[].class)).via(s -> s.getBytes(StandardCharsets.UTF_8))); bytes.apply(TFRecordWriteSchemaTransformProvider...); // field type BYTES
Defensive patterns
Strategy: type-guard
Validate before calling
Schema s = pc.getSchema();
if (s.getFieldCount() == 1 && !s.getField(0).getType().equals(Schema.FieldType.BYTES)) {
throw new IllegalArgumentException("Sole field must be BYTES, got " + s.getField(0).getType());
} Type guard
static boolean isBytesTyped(PCollection<?> pc) {
Schema s = pc.getSchema();
return s.getFieldCount() == 1 && s.getField(0).getType().equals(Schema.FieldType.BYTES);
} Try / catch
try { pc.apply(tfRecordWrite); } catch (IllegalArgumentException e) { if (e.getMessage().contains("exactly one field of type byte")) { log.error("Field {} is {}; convert to byte[] first", pc.getSchema().getField(0).getName(), pc.getSchema().getField(0).getType()); } throw e; } Prevention
- Explicitly serialize (UTF-8, protobuf, or Row.toBytes) so the field type is BYTES.
- Prefer Parquet/Avro transforms for typed structured data.
When it happens
Trigger: Applying the TFRecord write SchemaTransform to a PCollection whose sole schema field is a non-BYTES type (STRING, INT64, ROW, etc.).
Common situations: Writing strings or numeric values directly without converting to byte[]; a prior transform leaving the field typed as VARCHAR/STRING; assuming the provider auto-serializes.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Expecting exactly one field, found
- Cannot merge two types: +fieldType1.getTypeName()+ and +fiel
- value type is '%s' for field type '%s'
- Unreachable case for Beam typename %s
- Problem converting field %s expected type: %s
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/c601e7cebf53fc6f.
Report an issue: GitHub.