{"record":{"id":"39a3bd0f4fc36f09","repo":"apache/iceberg","slug":"expected-json-object-for-record-value-after-parsin","errorCode":null,"errorMessage":"Expected json object for record.value after parsing: ${collectRecordDetails(record)}","messagePattern":"Expected json object for record\\.value after parsing: (.+?)","errorType":"exception","errorClass":"JsonToMapException","httpStatus":null,"severity":"error","filePath":"kafka-connect/kafka-connect-transforms/src/main/java/org/apache/iceberg/connect/transforms/JsonToMapTransform.java","lineNumber":89,"sourceCode":"  private R process(R record) {\n    if (!(record.value() instanceof String)) {\n      throw new JsonToMapException(\"record value is not a string, use StringConverter\");\n    }\n\n    String json = (String) record.value();\n    JsonNode obj;\n\n    try {\n      obj = MAPPER.readTree(json);\n    } catch (Exception e) {\n      throw new JsonToMapException(\n          String.format(\n              \"record.value is not valid json for record.value: %s\", collectRecordDetails(record)),\n          e);\n    }\n\n    if (!(obj instanceof ObjectNode)) {\n      throw new JsonToMapException(\n          String.format(\n              \"Expected json object for record.value after parsing: %s\",\n              collectRecordDetails(record)));\n    }\n\n    if (startAtRoot) {\n      return singleField(record, (ObjectNode) obj);\n    }\n    return structRecord(record, (ObjectNode) obj);\n  }\n\n  private R singleField(R record, ObjectNode obj) {\n    Struct struct =\n        new Struct(JSON_MAP_SCHEMA)\n            .put(ALL_JSON_SCHEMA_FIELD, JsonToMapUtils.populateMap(obj, Maps.newHashMap()));\n    return record.newRecord(\n        record.topic(),\n        record.kafkaPartition(),","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/kafka-connect/kafka-connect-transforms/src/main/java/org/apache/iceberg/connect/transforms/JsonToMapTransform.java#L71-L107","documentation":"JsonToMapTransform requires the parsed JSON to be an object (Jackson ObjectNode). If the value parses successfully but is an array, string, number, or boolean at the root, it throws JsonToMapException('Expected json object for record.value after parsing: ...') because the result must convert to a Map for Iceberg column mapping.","triggerScenarios":"record.value() is valid JSON but its root is a JSON array (e.g. '[1,2,3]'), a quoted string, a number, or null — anything not a '{...}' object.","commonSituations":"Topics carrying JSON arrays of events instead of single objects; producers emitting scalar JSON payloads; batch-export producers writing newline-batched arrays.","solutions":["Change the producer to emit a top-level JSON object per record","Wrap arrays in an object upstream (e.g. {\"records\": [...]}) and extract a field via a nested transform","Split array elements into individual records before the sink","Validate topic payloads with kafka-console-consumer to confirm the shape"],"exampleFix":"// before (producer)\n[{\"id\":1},{\"id\":2}]\n// after (one object per record)\n{\"id\":1}\n{\"id\":2}","handlingStrategy":"validation","validationCode":"boolean isJsonObjectPayload(String s) {\n  try { return new ObjectMapper().readTree(s) instanceof ObjectNode; } catch (Exception e) { return false; }\n}","typeGuard":"boolean isObjectNode(JsonNode n) {\n  return n instanceof ObjectNode;\n}","tryCatchPattern":"try {\n  return transform.apply(record);\n} catch (JsonToMapException e) {\n  LOG.error(\"Root JSON value must be an object\", e);\n  deadLetterQueue.send(record, e);\n  return null;\n}","preventionTips":["Ensure producers emit top-level JSON objects, never arrays/scalars","Add a contract test validating payload shape at the producer","Validate topic samples with kafka-console-consumer before enabling the sink"],"tags":["kafka-connect","smt","json","shape-mismatch"],"backgroundTag":"unexpected-response-shape","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}