{"record":{"id":"892ecfbc447922fb","repo":"pentaho/pentaho-kettle","slug":"avroinput-error-unsupportedtoplevelstructure","errorCode":"AvroInput.Error.UnsupportedTopLevelStructure","errorMessage":"AvroInput.Error.UnsupportedTopLevelStructure","messagePattern":"AvroInput\\.Error\\.UnsupportedTopLevelStructure","errorType":"exception","errorClass":"KettleException","httpStatus":null,"severity":"error","filePath":"plugins/avro-format/core/src/main/java/org/pentaho/di/trans/steps/avro/input/AvroNestedReader.java","lineNumber":332,"sourceCode":"      }\n\n      m_topLevelRecord = new GenericData.Record( firstUnion );\n      if ( setDefault ) {\n        m_defaultTopLevelObject = m_topLevelRecord;\n      }\n    } else if ( schema.getType() == Schema.Type.ARRAY ) {\n      m_topLevelArray = new GenericData.Array( 1, schema ); // capacity,\n      // schema\n      if ( setDefault ) {\n        m_defaultTopLevelObject = m_topLevelArray;\n      }\n    } else if ( schema.getType() == Schema.Type.MAP ) {\n      m_topLevelMap = new HashMap<Utf8, Object>();\n      if ( setDefault ) {\n        m_defaultTopLevelObject = m_topLevelMap;\n      }\n    } else {\n      throw new KettleException( BaseMessages.getString( PKG,\n        \"AvroInput.Error.UnsupportedTopLevelStructure\" ) );\n    }\n  }\n\n  /**\n   * Examines the user-specified paths for the presence of a map/array expansion. If such an expansion is detected it\n   * checks that it is valid and, if so, creates an expansion handler for processing it.\n   *\n   * @param normalFields  the original user-specified paths. This is modified to contain only non-expansion paths.\n   * @param outputRowMeta the output row format\n   * @return an AvroArrayExpansion object to handle expansions or null if no expansions are present in the user-supplied\n   * path definitions.\n   * @throws KettleException if a problem occurs\n   */\n  protected AvroArrayExpansion checkFieldPaths( List<AvroInputField> normalFields,\n                                                RowMetaInterface outputRowMeta ) throws\n    KettleException {\n    // here we check whether there are any full map/array expansions","sourceCodeStart":314,"sourceCodeEnd":350,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/plugins/avro-format/core/src/main/java/org/pentaho/di/trans/steps/avro/input/AvroNestedReader.java#L314-L350","documentation":"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.","triggerScenarios":"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().","commonSituations":"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.","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."],"exampleFix":"// before: top-level enum schema\n{\"type\": \"enum\", \"name\": \"Color\", \"symbols\": [\"RED\",\"GREEN\"]}\n// after: wrap in a record\n{\"type\": \"record\", \"name\": \"ColorRec\", \"fields\": [{\"name\": \"color\", \"type\": {\"type\": \"enum\", \"name\": \"Color\", \"symbols\": [\"RED\",\"GREEN\"]}}]}","handlingStrategy":"validation","validationCode":"// Before init, validate the schema root type\nSchema.Type t = schema.getType();\nif (!(t == Schema.Type.RECORD || t == Schema.Type.ARRAY || t == Schema.Type.MAP\n      || (t == Schema.Type.UNION && schema.getTypes().stream()\n          .anyMatch(s -> s.getType() == Schema.Type.RECORD)))) {\n  throw new IllegalArgumentException(\"Unsupported top-level Avro schema type: \" + t);\n}","typeGuard":"boolean hasSupportedRoot(Schema s) {\n  Schema.Type t = s.getType();\n  return t == Schema.Type.RECORD || t == Schema.Type.ARRAY || t == Schema.Type.MAP\n      || (t == Schema.Type.UNION && s.getTypes().stream()\n           .anyMatch(u -> u.getType() == Schema.Type.RECORD));\n}","tryCatchPattern":"try {\n  step.init(...);\n} catch (KettleException e) {\n  if (e.getMessage().contains(\"UnsupportedTopLevelStructure\")) {\n    // fall back to a record-wrapped schema or skip this input\n  } else throw e;\n}","preventionTips":["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"],"tags":["avro","schema","initialization","pdi"],"backgroundTag":"unsupported-operation","analyzedSha":"f3058517a153da500bf4551f46d79b91bf8ec552","analyzedAt":"2026-09-13T14:04:16.340Z","contentChangedAt":"2026-09-13T14:04:16.340Z","schemaVersion":2},"datasetVersion":"2026-09-20T23:17:15.980Z"}