{"record":{"id":"5c8faaf715114a7d","repo":"apache/druid","slug":"first-token-should-be-start-array-but-it-is-actua","errorCode":null,"errorMessage":"First token should be START_ARRAY, but it is actually [%s]","messagePattern":"First token should be START_ARRAY, but it is actually \\[(.+?)\\]","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/data/input/impl/prefetch/JsonIterator.java","lineNumber":119,"sourceCode":"      jp.nextToken();\n      return retVal;\n    }\n    catch (IOException e) {\n      throw new RuntimeException(e);\n    }\n  }\n\n  private void init()\n  {\n    try {\n      if (inputStream == null) {\n        throw new UnsupportedOperationException();\n      } else {\n        jp = objectMapper.getFactory().createParser(inputStream);\n      }\n      final JsonToken nextToken = jp.nextToken();\n      if (nextToken != JsonToken.START_ARRAY) {\n        throw new IAE(\"First token should be START_ARRAY, but it is actually [%s]\", jp.getCurrentToken());\n      } else {\n        jp.nextToken();\n        objectCodec = jp.getCodec();\n      }\n    }\n    catch (IOException e) {\n      throw new RuntimeException(e);\n    }\n  }\n\n  @Override\n  public void close() throws IOException\n  {\n    CloseableUtils.closeAll(jp, resourceCloser);\n  }\n}\n","sourceCodeStart":101,"sourceCodeEnd":136,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/data/input/impl/prefetch/JsonIterator.java#L101-L136","documentation":"JsonIterator (prefetch-based JSON input) expects the input stream to be a top-level JSON array so it can iterate elements as rows. If Jackson's first token is anything other than START_ARRAY, it throws this IllegalArgumentException naming the actual token.","triggerScenarios":"Pointing a JSON input format at a file whose root is a single JSON object, NDJSON stream, scalar, or other non-array JSON - init() reads the first token and finds e.g. START_OBJECT or VALUE_STRING.","commonSituations":"NDJSON (newline-delimited objects) files fed where a JSON array is required, single object files, concatenated JSON without wrapping array, wrong inputFormat chosen for the data shape.","solutions":["Wrap the data in a top-level JSON array ([{...},{...}])","Or use the correct inputFormat for NDJSON data instead of the array-expecting one","Convert the file with jq -s '.' to produce an array","Check the actual token reported in the message to confirm the data shape"],"exampleFix":"// before (ndjson)\n{\"a\":1}\n{\"a\":2}\n// after (array)\n[{\"a\":1},{\"a\":2}]","handlingStrategy":"validation","validationCode":"try (JsonParser jp = new JsonFactory().createParser(in)) { if (jp.nextToken() != JsonToken.START_ARRAY) { /* not a JSON array */ } }","typeGuard":"boolean isJsonArray(InputStream in) { try { return new JsonFactory().createParser(in).nextToken() == JsonToken.START_ARRAY; } catch (IOException e) { return false; } }","tryCatchPattern":"try { iterator.forEachRemaining(r -> consume(r)); } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"START_ARRAY\")) { /* switch inputFormat */ } }","preventionTips":["Ensure data files are wrapped in a top-level JSON array","Use the NDJSON-appropriate inputFormat for newline-delimited objects","Spot-check the first bytes of files before ingestion"],"tags":["json","input-format","validation"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}