apache/druid · error · BadQueryContextException

Expected key [%s] to be an Integer, but got [%s]

Error message

Expected key [%s] to be an Integer, but got [%s]

What it means

QueryContexts.getAsInt(key, value) throws badTypeException with this message when the context value is neither null, a Number, nor a String — i.e. the type itself cannot even be attempted as an integer (Boolean, Map, List, etc.). Note this is distinct from the string-parse failure: here the value's class is simply wrong for an integer read.

Source

Thrown at processing/src/main/java/org/apache/druid/query/QueryContexts.java:383

    } else if (value instanceof String) {
      try {
        return Numbers.parseInt(value);
      }
      catch (NumberFormatException ignored) {

        // Attempt to handle trivial decimal values: 12.00, etc.
        // This mimics how Jackson will convert "12.00" to a Integer on request.
        try {
          return new BigDecimal((String) value).intValueExact();
        }
        catch (Exception nfe) {
          // That didn't work either. Give up.
          throw badValueException(key, "in integer format", value);
        }
      }
    }

    throw badTypeException(key, "an Integer", value);
  }

  /**
   * Get the value of a context value as an {@code int}. The value is expected
   * to be {@code null}, a string or a {@code Number} object.
   */
  public static int getAsInt(
      final String key,
      final Object value,
      final int defaultValue
  )
  {
    Integer val = getAsInt(key, value);
    return val == null ? defaultValue : val;
  }

  @Nullable
  public static Long getAsLong(String key, Object value)

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Fix the query context JSON so the key holds a JSON number or numeric string.
  2. If building contexts in code, put an Integer/Long: context.put(key, 100).
  3. Verify the key name — a nested object under this key often means the config was placed under the wrong context key.
  4. Catch the exception and fall back to the default value for the context key.

Example fix

// before
{"maxScatterGatherBytes": {"bytes": 100}}  // object -> IAE
// after
{"maxScatterGatherBytes": 100}
Defensive patterns

Strategy: type-guard

Validate before calling

Object v = context.get(key);
if (v != null && !(v instanceof Number) && !(v instanceof String)) {
  throw new IllegalArgumentException("Context key '" + key + "' must be numeric, got: " + v.getClass().getSimpleName());
}

Type guard

boolean isContextNumber(Object v) { return v == null || v instanceof Number || v instanceof String; }

Try / catch

try {
  return query.getContextValue(key, defaultInt);
} catch (IllegalArgumentException e) {
  LOG.warn(e, "Wrong type for context key [%s], using default", key);
  return defaultInt;
}

Prevention

When it happens

Trigger: Calling QueryContexts.getAsInt(key, value) or query.getContextValue(key, int default) when the context map holds a Boolean, JSONArray, JSONObject, or other non-numeric, non-string object for an integer-typed context key.

Common situations: A client sends an integer context key as a JSON object or array (e.g. nested config pasted into the wrong key); a boolean flag accidentally placed under a numeric key; serialization frameworks that deserialized the value into a non-numeric type.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/02d9ee0611494b50. Report an issue: GitHub.