{"record":{"id":"59f232c36b6cdad3","repo":"apache/druid","slug":"next-token-wasn-t-a-start-array-was-s-from-url","errorCode":null,"errorMessage":"Next token wasn't a START_ARRAY, was[%s] from url[%s] with value[%s]","messagePattern":"Next token wasn't a START_ARRAY, was\\[(.+?)\\] from url\\[(.+?)\\] with value\\[(.+?)\\]","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"server/src/main/java/org/apache/druid/client/JsonParserIterator.java","lineNumber":202,"sourceCode":"          // this exception thrown for other reasons, it would be great to document what other reasons this can happen.\n          throw ResourceLimitExceededException.withMessage(\n              \"Possibly max scatter-gather bytes limit reached while reading from url[%s].\",\n              url\n          );\n        }\n\n        final JsonToken nextToken = jp.nextToken();\n        if (nextToken == JsonToken.START_ARRAY) {\n          jp.nextToken();\n          objectCodec = jp.getCodec();\n        } else if (nextToken == JsonToken.START_OBJECT) {\n          throw convertException(jp.getCodec().readValue(jp, QueryException.class));\n        } else {\n          String errMsg = jp.getValueAsString();\n          if (errMsg != null) {\n            errMsg = errMsg.substring(0, Math.min(errMsg.length(), 192));\n          }\n          throw convertException(\n              new IAE(\n                  \"Next token wasn't a START_ARRAY, was[%s] from url[%s] with value[%s]\",\n                  jp.getCurrentToken(),\n                  url,\n                  errMsg\n              )\n          );\n        }\n      }\n      catch (ExecutionException | CancellationException e) {\n        throw convertException(e.getCause() == null ? e : e.getCause());\n      }\n      catch (IOException | InterruptedException e) {\n        throw convertException(e);\n      }\n      catch (TimeoutException e) {\n        throw new QueryTimeoutException(StringUtils.nonStrictFormat(\"Query [%s] timed out!\", queryId), host);\n      }","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/server/src/main/java/org/apache/druid/client/JsonParserIterator.java#L184-L220","documentation":"JsonParserIterator expects the HTTP response body to start with a JSON START_ARRAY token (the standard Druid results array). If the first token is anything else, init() throws this IAE showing the actual token type, the URL, and a truncated (192-char) snapshot of the payload. This usually means the server returned an error or non-standard JSON object instead of the expected results array.","triggerScenarios":"The response stream from url[%s] parses to a token that is not START_ARRAY — e.g. a JSON error object {\"error\":...}, a bare string, or HTML from a misbehaving proxy — encountered when hasNext()/next() call init().","commonSituations":"Downstream server returning a serialized QueryException or plain error JSON, an intermediate proxy/load balancer replacing the body with an HTML error page, or API/protocol mismatch between broker and older/newer data node versions.","solutions":["Read the value[%s] in the message: it usually contains the real server error; fix that underlying issue first","Confirm broker and data node versions are compatible (rolling-upgrade skew can change response shapes)","Check for proxies/load balancers intercepting the URL and returning non-JSON bodies","Retry the query; if persistent, capture the raw response from the data node endpoint for diagnosis"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// verify cluster version skew before issuing queries\n// all data nodes should report the same/major-compatible version as the broker","typeGuard":null,"tryCatchPattern":"try {\n  stream = iterator; // triggers init()\n} catch (IAE e) {\n  if (e.getMessage().startsWith(\"Next token wasn't a START_ARRAY\")) {\n    // log full message: contains upstream error payload in value[...]\n    // surface underlying server error, do not blindly retry\n  }\n}","preventionTips":["Inspect the value[...] field in the message — it usually carries the real server error","Keep broker and data node versions compatible during rolling upgrades","Bypass or fix proxies that return HTML error pages on the query path","Retry only after confirming the upstream error is transient"],"tags":["json","http-response","protocol-mismatch","query-execution"],"backgroundTag":"unexpected-response-shape","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}