{"record":{"id":"a5be68e6d6a0a302","repo":"apache/druid","slug":"expected-key-s-to-be-csv-or-json-array-but-got","errorCode":null,"errorMessage":"Expected key [%s] to be CSV or JSON array, but got [%s]","messagePattern":"Expected key \\[(.+?)\\] to be CSV or JSON array, but got \\[(.+?)\\]","errorType":"exception","errorClass":"BadQueryContextException","httpStatus":null,"severity":"error","filePath":"multi-stage-query/src/main/java/org/apache/druid/msq/util/MultiStageQueryContext.java","lineNumber":720,"sourceCode":"    return queryContext.getInt(CTX_SEGMENT_LOAD_AHEAD_COUNT);\n  }\n\n  /**\n   * Decodes a list from either a JSON or CSV string.\n   */\n  @VisibleForTesting\n  static List<String> decodeList(final String keyName, @Nullable final String listString)\n  {\n    if (listString == null) {\n      return Collections.emptyList();\n    } else if (LOOKS_LIKE_JSON_ARRAY.matcher(listString).matches()) {\n      try {\n        // Not caching this ObjectMapper in a static, because we expect to use it infrequently (once per INSERT\n        // query that uses this feature) and there is no need to keep it around longer than that.\n        return new ObjectMapper().readValue(listString, new TypeReference<>() {});\n      }\n      catch (JsonProcessingException e) {\n        throw QueryContexts.badValueException(keyName, \"CSV or JSON array\", listString);\n      }\n    } else {\n      final RFC4180Parser csvParser = new RFC4180ParserBuilder().withSeparator(',').build();\n\n      try {\n        return Arrays.stream(csvParser.parseLine(listString))\n                     .filter(s -> s != null && !s.isEmpty())\n                     .map(String::trim)\n                     .collect(Collectors.toList());\n      }\n      catch (IOException e) {\n        throw QueryContexts.badValueException(keyName, \"CSV or JSON array\", listString);\n      }\n    }\n  }\n\n  /**\n   * Decodes {@link #CTX_INDEX_SPEC} from either a JSON-encoded string, or POJOs.","sourceCodeStart":702,"sourceCodeEnd":738,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/multi-stage-query/src/main/java/org/apache/druid/msq/util/MultiStageQueryContext.java#L702-L738","documentation":"Query context key parsing in MultiStageQueryContext expects a value that is either a comma-separated string or a JSON array string. When Jackson fails to parse the string as a JSON array (JsonProcessingException) in the JSON branch, Druid throws QueryContexts.badValueException stating the key must be a CSV or JSON array. This is a query-context validation error, so the query is rejected before execution.","triggerScenarios":"Calling MultiStageQueryContext.getListStringFromContext-style parsing (e.g. for CTX_TASK_STORAGE_DIR or partitioning keys) with a query context value like '{\"a\":1}' or a malformed JSON string such as '[\"a\", ' that is not valid JSON, in the branch where the value is treated as JSON rather than CSV.","commonSituations":"Users pass the context value as JSON via a client that double-encodes or single-quotes strings (e.g. '[\"a\",\"b\"]' with unescaped quotes), or a BI tool submits the context key as an object rather than a JSON-encoded string.","solutions":["Pass the value as a simple comma-separated CSV string instead, e.g. \"a,b,c\", which avoids the JSON parser entirely.","If using JSON, ensure it is a valid JSON array literal with double quotes: [\"a\",\"b\"] with no trailing commas or single quotes.","Verify the client is not double-encoding the value (a string containing escaped quotes like \\\" indicates double encoding)."],"exampleFix":"// before\nqueryContext.put(\"partitionKeys\", \"[\\\"country\\\", 'region]\");\n// after\nqueryContext.put(\"partitionKeys\", \"country,region\");","handlingStrategy":"validation","validationCode":"String v = (String) queryContext.get(\"myListKey\");\nif (v != null && v.trim().startsWith(\"[\")) {\n  try { new ObjectMapper().readValue(v, List.class); }\n  catch (JsonProcessingException e) { throw new IllegalArgumentException(\"key must be CSV or a valid JSON array: \" + v); }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer plain CSV strings (\"a,b,c\") for list-valued MSQ context keys.","Never single-quote or trailing-comma JSON arrays in context values.","Beware client double-encoding of JSON strings in HTTP/SQL clients."],"tags":["druid","msq","query-context","json","csv"],"backgroundTag":"invalid-argument-format","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"}