apache/druid · error · ParseException
Unable to parse row [%s]
Error message
Unable to parse row [%s]
What it means
JSONPathParser.parseToMap parses an input string as JSON with Jackson and flattens the resulting JsonNode into a Map using a JSONPath/JSON-flattener spec. If Jackson cannot parse the input as JSON, or the flattening step fails, the parser wraps the cause in a ParseException reporting the offending raw row.
Source
Thrown at processing/src/main/java/org/apache/druid/java/util/common/parsers/JSONPathParser.java:77
{
}
/**
* @param input JSON string. The root must be a JSON object, not an array.
* e.g., {"valid": "true"} and {"valid":[1,2,3]} are supported
* but [{"invalid": "true"}] and [1,2,3] are not.
*
* @return A map of field names and values
*/
@Override
public Map<String, Object> parseToMap(String input)
{
try {
JsonNode document = mapper.readValue(input, JsonNode.class);
return flattener.flatten(document);
}
catch (Exception e) {
throw new ParseException(input, e, "Unable to parse row [%s]", input);
}
}
}
View on GitHub (pinned to 9b90983fd2)
Solutions
- Validate and fix the input data: ensure each record is a single, well-formed JSON object.
- Verify the ingestion spec uses the correct parser (e.g. 'string' JSON parser, not JSONPath) for the actual data format.
- Check for encoding/truncation issues at the source (char-set mismatch, partial reads).
- If flatten spec fields don't match the document shape, correct the flattenSpec (useFieldDiscovery, paths).
- Catch ParseException in the ingestion path and route bad rows to a dead-letter/sink instead of failing the task.
Example fix
// before
Map<String, Object> row = new JSONPathParser(flattenSpec).parseToMap(rawLine); // rawLine may be "{a:1}{b:2}"
// after
ObjectMapper mapper = new ObjectMapper();
if (rawLine == null || rawLine.trim().isEmpty()) { continue; }
try {
mapper.readTree(rawLine); // pre-validate
} catch (IOException e) { sendToDeadLetter(rawLine); continue; }
Map<String, Object> row = parser.parseToMap(rawLine); Defensive patterns
Strategy: try-catch
Validate before calling
private static boolean isValidJson(final ObjectMapper mapper, final String input) {
if (input == null || input.trim().isEmpty()) { return false; }
try { mapper.readTree(input); return true; } catch (IOException e) { return false; }
} Try / catch
try {
Map<String, Object> row = parser.parseToMap(input);
} catch (ParseException e) {
log.warn(e, "Skipping unparseable row: %s", input);
// forward to dead-letter topic / reject report
} Prevention
- Pre-validate payloads are single well-formed JSON objects at the producer.
- Match parser type to data format (don't use JSONPathParser for non-JSON).
- Keep flattenSpec paths consistent with the actual document shape.
- Monitor ingestion reject counts to catch producer regressions early.
When it happens
Trigger: Calling parseToMap(String) (or the generic Parser interface used by ingestion) with input that is not valid JSON (truncated line, concatenated JSON objects, CSV/plain text), or JSON whose structure defeats the configured flattener (e.g. usingField/path mismatches causing flatten exceptions).
Common situations: Kafka/Kinesis records that are not pure JSON (e.g. Avro-encoded or newline-delimited batches fed as single rows); empty strings from skipped queue messages; encoding issues corrupting payloads; wrong parser chosen for the data format.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Unable to parse row [%s]
- Illegal segmentId format [%s]
- JavaScript parsed value [%s] must be in {key: value} format!
- Value [%s] is not valid for property [%s]
- Unable to parse line.
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/991b80ab103845df.
Report an issue: GitHub.