apache/druid · error · BadQueryContextException

Expected key [%s] to be a Long, but got [%s]

Error message

Expected key [%s] to be a Long, but got [%s]

What it means

QueryContexts.getAsLong(key, value) throws badTypeException with this message when the context value's class cannot be interpreted as a Long at all — it is neither null, a Number, nor a String (e.g. Boolean, Map, List). The exception includes the key and the value's actual type.

Source

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

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

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

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

  /**
   * Get the value of a context value as an {@code Float}. The value is expected

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Correct the context JSON so the key holds a JSON number or numeric string.
  2. In code, put a Long/Integer: context.put(key, 123456789L).
  3. Check for key-name typos that cause a value of the wrong shape to land under this key.
  4. Catch the exception and fall back to the default value.

Example fix

// before
{"timeout": false}   // boolean under numeric key -> IAE
// after
{"timeout": 30000}
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, defaultLong);
} catch (IllegalArgumentException e) {
  LOG.warn(e, "Wrong type for context key [%s], using default", key);
  return defaultLong;
}

Prevention

When it happens

Trigger: Calling QueryContexts.getAsLong(key, value) or query.getContextValue(key, long default) when the context map stores a Boolean, JSON object/array, or other non-numeric non-string object under a long-typed context key.

Common situations: A boolean or nested-config value placed under a numeric key by mistake; clients sending JSON objects where a number is expected; earlier code paths that stored raw deserialized JSON trees into the context.

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/cfbce57e8dea0bee. Report an issue: GitHub.