{"record":{"id":"c506d82a54a0edd4","repo":"apache/druid","slug":"unable-to-parse-row-s-c506d8","errorCode":null,"errorMessage":"Unable to parse row [%s]","messagePattern":"Unable to parse row \\[(.+?)\\]","errorType":"exception","errorClass":"ParseException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/java/util/common/parsers/JSONToLowerParser.java","lineNumber":147,"sourceCode":"          final List<Object> nodeValue = Lists.newArrayListWithExpectedSize(node.size());\n          for (final JsonNode subnode : node) {\n            final Object subnodeValue = VALUE_FUNCTION.apply(subnode);\n            if (subnodeValue != null) {\n              nodeValue.add(subnodeValue);\n            }\n          }\n          map.put(StringUtils.toLowerCase(key), nodeValue); // difference from JSONParser parse()\n        } else {\n          final Object nodeValue = VALUE_FUNCTION.apply(node);\n          if (nodeValue != null) {\n            map.put(StringUtils.toLowerCase(key), nodeValue); // difference from JSONParser parse()\n          }\n        }\n      }\n      return map;\n    }\n    catch (Exception e) {\n      throw new ParseException(input, e, \"Unable to parse row [%s]\", input);\n    }\n  }\n}\n","sourceCodeStart":129,"sourceCodeEnd":151,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/java/util/common/parsers/JSONToLowerParser.java#L129-L151","documentation":"JSONToLowerParser.parseToMap parses a JSON row and lowercases all keys (and optionally values) so ingestion is case-insensitive. Any failure while parsing the JSON or building the lowered map is wrapped in a ParseException with the raw input text as the message detail.","triggerScenarios":"Calling parseToMap(String) with input that is not a valid JSON object (malformed JSON, empty/null string, non-object top-level value whose handling breaks key lowering), or an element whose processing (e.g. flattening nested maps) throws.","commonSituations":"Feeding newline-delimited JSON where a record was split mid-object; passing plain-text or CSV rows to a JSON parser; null/empty messages from a message bus; numeric or array top-level JSON values instead of objects.","solutions":["Ensure each input record is a complete, valid JSON object before parsing.","Fix upstream producers so records are not truncated or concatenated.","Use the appropriate parser type for the actual payload format.","Skip or quarantine rows that are empty/null before calling the parser.","Catch ParseException per-row in ingestion code and log/forward the bad record instead of aborting."],"exampleFix":"// before\nMap<String, Object> row = parser.parseToMap(record.value()); // may throw ParseException\n// after\nString input = record.value();\ntry {\n  Map<String, Object> row = parser.parseToMap(input);\n} catch (ParseException e) {\n  log.warn(e, \"Bad row, skipping: %s\", input);\n}\n","handlingStrategy":"try-catch","validationCode":"private static boolean isParsableJsonObject(final ObjectMapper mapper, final String input) {\n  if (input == null || input.trim().isEmpty()) { return false; }\n  try {\n    return mapper.readTree(input).isObject();\n  } catch (IOException e) { return false; }\n}","typeGuard":null,"tryCatchPattern":"try {\n  Map<String, Object> row = parser.parseToMap(input);\n} catch (ParseException e) {\n  log.warn(e, \"Bad row skipped: %s\", input);\n}","preventionTips":["Ensure records are complete JSON objects (no mid-line splits in NDJSON).","Reject null/empty messages before parsing.","Use the correct parser for the payload format.","Route parse failures to a reject/dead-letter path instead of failing ingestion."],"tags":["json","parsing","ingestion","parseexception"],"backgroundTag":"json-parse-error","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}