apache/iceberg · error · JsonToMapException
Expected json object for record.value after parsing
Error message
Expected json object for record.value after parsing: ${collectRecordDetails(record)} What it means
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.
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
Example fix
// before (producer)
[{"id":1},{"id":2}]
// after (one object per record)
{"id":1}
{"id":2} Defensive patterns
Strategy: validation
Validate before calling
boolean isJsonObjectPayload(String s) {
try { return new ObjectMapper().readTree(s) instanceof ObjectNode; } catch (Exception e) { return false; }
} Type guard
boolean isObjectNode(JsonNode n) {
return n instanceof ObjectNode;
} Try / catch
try {
return transform.apply(record);
} catch (JsonToMapException e) {
LOG.error("Root JSON value must be an object", e);
deadLetterQueue.send(record, e);
return null;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: Topics carrying JSON arrays of events instead of single objects; producers emitting scalar JSON payloads; batch-export producers writing newline-batched arrays.
Related errors
- record value is not a string, use StringConverter
- record.value is not valid json for record.value
- Could not parse for
- parsing binary value threw exception for
- Schema not support for DMS records
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/39a3bd0f4fc36f09.
Report an issue: GitHub.
Appendix: source
Thrown at kafka-connect/kafka-connect-transforms/src/main/java/org/apache/iceberg/connect/transforms/JsonToMapTransform.java:89
private R process(R record) {
if (!(record.value() instanceof String)) {
throw new JsonToMapException("record value is not a string, use StringConverter");
}
String json = (String) record.value();
JsonNode obj;
try {
obj = MAPPER.readTree(json);
} catch (Exception e) {
throw new JsonToMapException(
String.format(
"record.value is not valid json for record.value: %s", collectRecordDetails(record)),
e);
}
if (!(obj instanceof ObjectNode)) {
throw new JsonToMapException(
String.format(
"Expected json object for record.value after parsing: %s",
collectRecordDetails(record)));
}
if (startAtRoot) {
return singleField(record, (ObjectNode) obj);
}
return structRecord(record, (ObjectNode) obj);
}
private R singleField(R record, ObjectNode obj) {
Struct struct =
new Struct(JSON_MAP_SCHEMA)
.put(ALL_JSON_SCHEMA_FIELD, JsonToMapUtils.populateMap(obj, Maps.newHashMap()));
return record.newRecord(
record.topic(),
record.kafkaPartition(),View on GitHub (pinned to 86d9c8fc54)