{"record":{"id":"7e64e7173343b11d","repo":"apache/druid","slug":"not-a-scalar-in-the-dictionary","errorCode":null,"errorMessage":"not a scalar in the dictionary","messagePattern":"not a scalar in the dictionary","errorType":"exception","errorClass":"java.lang.IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/segment/nested/NestedFieldDictionaryEncodedColumn.java","lineNumber":274,"sourceCode":"          if (candidate >= 0) {\n            candidate += adjustDoubleId;\n          }\n        }\n      }\n      return candidate;\n    }\n  }\n\n  private Object lookupGlobalScalarObject(int globalId)\n  {\n    if (globalId < adjustLongId) {\n      return StringUtils.fromUtf8Nullable(globalDictionary.get(globalId));\n    } else if (globalId < adjustDoubleId) {\n      return globalLongDictionary.get(globalId - adjustLongId);\n    } else if (globalId < adjustArrayId) {\n      return globalDoubleDictionary.get(globalId - adjustDoubleId);\n    }\n    throw new IllegalArgumentException(\"not a scalar in the dictionary\");\n  }\n\n\n  /**\n   * Lookup value from appropriate scalar value dictionary, coercing the value to {@link #logicalType}, particularly\n   * useful for the vector query engine which prefers all the types are consistent\n   * <p>\n   * This method should NEVER be used when values must round trip to be able to be looked up from the array value\n   * dictionary since it might coerce element values to a different type\n   */\n  @Nullable\n  private Object lookupGlobalScalarValueAndCast(int globalId)\n  {\n\n    if (globalId == 0) {\n      return null;\n    }\n    if (singleType != null) {","sourceCodeStart":256,"sourceCodeEnd":292,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/segment/nested/NestedFieldDictionaryEncodedColumn.java#L256-L292","documentation":"NestedFieldDictionaryEncodedColumn.lookupGlobalScalarObject() maps a global dictionary id back to its scalar value (null, long, double, or string). The id ranges are partitioned by type; an id beyond the array-id adjustment boundary means it refers to an ARRAY entry, not a scalar, so IllegalArgumentException is thrown - scalars cannot be looked up through this method.","triggerScenarios":"Calling lookupGlobalScalarObject (directly or via lookupObject/eval/getObject on paths that expect scalars) with a global dictionary id that encodes an array value rather than a scalar.","commonSituations":"Vector/engine code or custom extensions walking all global dictionary ids including array entries; mis-computed id offsets after dictionary merge; querying an ARRAY field through scalar-expectant operators.","solutions":["Filter dictionary ids to the scalar range before calling lookupGlobalScalarObject (id < adjustArrayId).","Use the array-specific lookup path (e.g. lookupArrayGlobalObject / array dictionary APIs) for array-valued ids.","Check code that computes global ids so offsets (adjustLongId, adjustDoubleId, adjustArrayId) are computed from the same metadata version.","If hitting this from a query, cast or restructure the expression so array values are handled as arrays."],"exampleFix":"// before\nObject v = column.lookupGlobalScalarObject(globalId); // may be an array id\n// after\nif (globalId < column.getGlobalArrayIdBase()) {\n  Object v = column.lookupGlobalScalarObject(globalId);\n} else {\n  Object v = column.lookupArrayValue(globalId); // array path\n}","handlingStrategy":"validation","validationCode":"// only pass ids below the array boundary\nif (globalId >= adjustArrayId) {\n  throw new IllegalArgumentException(\"id refers to an array entry; use array lookup\");\n}","typeGuard":"boolean isScalarGlobalId(int globalId, int adjustArrayId) { return globalId < adjustArrayId; }","tryCatchPattern":"try {\n  Object v = col.lookupGlobalScalarObject(globalId);\n} catch (IllegalArgumentException e) {\n  if (\"not a scalar in the dictionary\".equals(e.getMessage())) {\n    v = col.lookupArrayValue(globalId);\n  } throw e;\n}","preventionTips":["Partition dictionary-id ranges by type before lookup","Use array lookup APIs for ids >= adjustArrayId","Keep id-offset computation in sync with the column metadata version"],"tags":["druid","nested-column","dictionary","type-mismatch"],"backgroundTag":"invalid-argument-value","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"}