pentaho/pentaho-kettle · error · KettleException
AvroInput.Error.UnsupportedTopLevelStructure
AvroInput.Error.UnsupportedTopLevelStructure
Error message
AvroInput.Error.UnsupportedTopLevelStructure
What it means
AvroNestedReader.initTopLevelStructure only supports Avro schemas whose top-level type is RECORD, UNION (containing at least one record), ARRAY, or MAP. Any other top-level type (e.g. STRING, INT, BYTES, DOUBLE, ENUM, FIXED) is not readable as a row container, so a KettleException is thrown during step init. This is a hard schema-shape restriction of the Avro Input step, not a data error.
Solutions
- Rewrap the data in a top-level RECORD: define a record with a field of the primitive/enum type and reference that record as the schema root.
- If the top-level type is a UNION, ensure it contains at least one RECORD branch (the reader uses the first record branch to seed the top-level object).
- If you only need the scalar value, use a different step (e.g. a User Defined Java Expression or a simpler file input) instead of the Avro Input step.
Example fix
// before: top-level enum schema
{"type": "enum", "name": "Color", "symbols": ["RED","GREEN"]}
// after: wrap in a record
{"type": "record", "name": "ColorRec", "fields": [{"name": "color", "type": {"type": "enum", "name": "Color", "symbols": ["RED","GREEN"]}}]} Defensive patterns
Strategy: validation
Validate before calling
// Before init, validate the schema root type
Schema.Type t = schema.getType();
if (!(t == Schema.Type.RECORD || t == Schema.Type.ARRAY || t == Schema.Type.MAP
|| (t == Schema.Type.UNION && schema.getTypes().stream()
.anyMatch(s -> s.getType() == Schema.Type.RECORD)))) {
throw new IllegalArgumentException("Unsupported top-level Avro schema type: " + t);
} Type guard
boolean hasSupportedRoot(Schema s) {
Schema.Type t = s.getType();
return t == Schema.Type.RECORD || t == Schema.Type.ARRAY || t == Schema.Type.MAP
|| (t == Schema.Type.UNION && s.getTypes().stream()
.anyMatch(u -> u.getType() == Schema.Type.RECORD));
} Try / catch
try {
step.init(...);
} catch (KettleException e) {
if (e.getMessage().contains("UnsupportedTopLevelStructure")) {
// fall back to a record-wrapped schema or skip this input
} else throw e;
} Prevention
- Always use a RECORD as the schema root for Avro Input steps
- If using a top-level UNION, ensure it contains a RECORD branch
- Lint schemas with a pre-flight script that checks Schema.getType() before deployment
When it happens
Trigger: Setting the step's schema to an Avro schema whose root type is a primitive (string/int/boolean/etc.), enum, or fixed type, then calling init() -> setSchemaToUse() -> initTopLevelStructure().
Common situations: Pointing the Avro Input step at a schema file meant for serializing a single scalar value; a hand-edited schema where the record was unwrapped to a top-level enum/fixed; tooling that generated a minimal schema wrapping one primitive.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- AvroInput.Error.UnableToFindSchemaForUnionMap
- AvroInput.Error.UnexpectedArrayElementTypeAtNonExpansionPoin…
- AvroInput.Error.CantLoadIncommingSchemaAndNoDefault
- AvroInput.Error.EncounteredAPrimitivePriorToMapExpansion
- AvroInput.Error.IncommingSchemaIsMissingAndNoDefault
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/892ecfbc447922fb.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/avro-format/core/src/main/java/org/pentaho/di/trans/steps/avro/input/AvroNestedReader.java:332
}
m_topLevelRecord = new GenericData.Record( firstUnion );
if ( setDefault ) {
m_defaultTopLevelObject = m_topLevelRecord;
}
} else if ( schema.getType() == Schema.Type.ARRAY ) {
m_topLevelArray = new GenericData.Array( 1, schema ); // capacity,
// schema
if ( setDefault ) {
m_defaultTopLevelObject = m_topLevelArray;
}
} else if ( schema.getType() == Schema.Type.MAP ) {
m_topLevelMap = new HashMap<Utf8, Object>();
if ( setDefault ) {
m_defaultTopLevelObject = m_topLevelMap;
}
} else {
throw new KettleException( BaseMessages.getString( PKG,
"AvroInput.Error.UnsupportedTopLevelStructure" ) );
}
}
/**
* Examines the user-specified paths for the presence of a map/array expansion. If such an expansion is detected it
* checks that it is valid and, if so, creates an expansion handler for processing it.
*
* @param normalFields the original user-specified paths. This is modified to contain only non-expansion paths.
* @param outputRowMeta the output row format
* @return an AvroArrayExpansion object to handle expansions or null if no expansions are present in the user-supplied
* path definitions.
* @throws KettleException if a problem occurs
*/
protected AvroArrayExpansion checkFieldPaths( List<AvroInputField> normalFields,
RowMetaInterface outputRowMeta ) throws
KettleException {
// here we check whether there are any full map/array expansionsView on GitHub (pinned to f3058517a1)