{"record":{"id":"ac05e8f94d45a72d","repo":"pentaho/pentaho-kettle","slug":"avroinput-error-unabletofindschemaforunionmap","errorCode":"AvroInput.Error.UnableToFindSchemaForUnionMap","errorMessage":"AvroInput.Error.UnableToFindSchemaForUnionMap","messagePattern":"AvroInput\\.Error\\.UnableToFindSchemaForUnionMap","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":483,"sourceCode":"\n    if ( valueType.getType() == Schema.Type.UNION ) {\n      if ( value instanceof GenericContainer ) {\n        // we can ask these things for their schema (covers\n        // records, arrays, enums and fixed)\n        valueType = ( (GenericContainer) value ).getSchema();\n      } else {\n        // either have a map or primitive here\n        if ( value instanceof Map ) {\n          // now have to look for the schema of the map\n          Schema mapSchema = null;\n          for ( Schema ts : valueType.getTypes() ) {\n            if ( ts.getType() == Schema.Type.MAP ) {\n              mapSchema = ts;\n              break;\n            }\n          }\n          if ( mapSchema == null ) {\n            throw new KettleException( BaseMessages.getString( PKG,\n              \"AvroInput.Error.UnableToFindSchemaForUnionMap\" ) );\n          }\n          valueType = mapSchema;\n        } else {\n          if ( avroInputField.getTempValueMeta().getType() != ValueMetaInterface.TYPE_STRING ) {\n            // we have a two element union, where one element is the type\n            // \"null\". So in this case we actually have just one type and can\n            // output specific values of it (instead of using String as a\n            // catch all for varying primitive types in the union)\n            valueType = checkUnion( valueType );\n          } else {\n            // use the string representation of the value\n            valueType = Schema.create( Schema.Type.STRING );\n          }\n        }\n      }\n    }\n","sourceCodeStart":465,"sourceCodeEnd":501,"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#L465-L501","documentation":"While resolving a MAP value whose schema is a UNION, convertToKettleValue scans the union's branches for a MAP-typed schema. If no branch is a MAP (and the remaining structure does not reduce to the two-element [type-marker, value] union case), the reader has no map schema to use and throws this KettleException.","triggerScenarios":"An Avro field is a union such as [\"null\",\"string\",\"long\"] but the field path/step config routes it into the map-conversion branch, so the code expects a map member inside the union and finds none.","commonSituations":"Generic Avro unions (record|map combos replaced upstream by non-map types); schema evolution changed a map into a union of scalars while paths still assume map semantics.","solutions":["Update the field path/Pentaho output type so the union is handled as its actual member type (e.g. string/long) instead of via map conversion.","Change the Avro schema so the union includes the expected MAP branch (e.g. [\"null\", {\"type\":\"map\",\"values\":\"string\"}]).","Unwrap the union upstream (normalize data before the Avro Input step) so the field arriving is a plain map."],"exampleFix":"// before\n{\"type\": [\"null\", \"string\", \"long\"]}\n// after (if map semantics intended)\n{\"type\": [\"null\", {\"type\": \"map\", \"values\": [\"string\", \"long\"]}]}","handlingStrategy":"validation","validationCode":"// Check that a union routed to map conversion contains a MAP branch\nif (unionSchema.getType() == Schema.Type.UNION\n    && unionSchema.getTypes().stream().noneMatch(s -> s.getType() == Schema.Type.MAP)) {\n  throw new IllegalArgumentException(\"Union has no map branch: \" + unionSchema);\n}","typeGuard":"boolean unionHasMapBranch(Schema s) {\n  return s.getType() == Schema.Type.UNION\n      && s.getTypes().stream().anyMatch(t -> t.getType() == Schema.Type.MAP);\n}","tryCatchPattern":"try {\n  Object v = reader.convertToKettleValue(...);\n} catch (KettleException e) {\n  if (e.getMessage().contains(\"UnableToFindSchemaForUnionMap\")) {\n    // read the field as its concrete union member type instead\n  } else throw e;\n}","preventionTips":["Inspect union branches in the schema before mapping fields","Avoid routing non-map unions through map-style paths","Version-check schemas after upstream changes"],"tags":["avro","schema","union","pdi"],"backgroundTag":"schema-validation-failed","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"}