apache/druid · error · BadQueryContextException
Expected key [%s] to be a String, but got [%s]
Error message
Expected key [%s] to be a String, but got [%s]
What it means
QueryContexts.getAs(String key, Object value) throws this when a query context value must be read as a String but the stored object is neither null nor a String. Druid query contexts are loosely-typed Map<String, Object> objects (often deserialized from JSON), so the context getters coerce values and fail loudly when the type cannot be coerced. The exception names the context key and the actual runtime type of the value.
Source
Thrown at processing/src/main/java/org/apache/druid/query/QueryContexts.java:325
@SuppressWarnings("unused") // To keep IntelliJ inspections happy
public static float parseFloat(Map<String, Object> context, String key, float defaultValue)
{
return getAsFloat(key, context.get(key), defaultValue);
}
public static String getAsString(
final String key,
final Object value,
final String defaultValue
)
{
if (value == null) {
return defaultValue;
} else if (value instanceof String) {
return (String) value;
}
throw badTypeException(key, "a String", value);
}
@Nullable
public static Boolean getAsBoolean(
final String key,
final Object value
)
{
if (value == null) {
return null;
} else if (value instanceof String) {
return Boolean.parseBoolean((String) value);
} else if (value instanceof Boolean) {
return (Boolean) value;
}
throw badTypeException(key, "a Boolean", value);
}
View on GitHub (pinned to 9b90983fd2)
Solutions
- Inspect the query context JSON sent by the client and change the offending key's value to a JSON string (quote it).
- If building queries programmatically, put a String into the context: context.put(key, String.valueOf(value)).
- Use QueryContexts.override(context, key, stringValue) to replace the bad value before executing.
- If the value legitimately is not a string, read it with the matching getter (getAsBoolean/getAsInt/getAsLong) instead of getAs.
Example fix
// before
context.put("queryId", 12345); // Integer
String id = query.getContextValue("queryId"); // throws
// after
context.put("queryId", "12345");
String id = query.getContextValue("queryId"); Defensive patterns
Strategy: type-guard
Validate before calling
Object v = context.get(key);
if (v != null && !(v instanceof String)) {
throw new IllegalArgumentException("Context key '" + key + "' must be a string, got: " + v.getClass().getSimpleName());
} Type guard
boolean isContextString(Object v) { return v == null || v instanceof String; } Try / catch
try {
return QueryContexts.getAs(key, context.get(key));
} catch (IllegalArgumentException e) {
LOG.warn(e, "Bad type for context key [%s], using default", key);
return defaultValue;
} Prevention
- Always send string-typed context keys as quoted JSON strings.
- Use QueryContexts.override() with typed values instead of raw map puts.
- Validate client-submitted query context against the query type's documented context schema before execution.
When it happens
Trigger: Calling QueryContexts.getAs(key, context.get(key)) (or query.getContextValue overloads that route through it) when the context map holds a non-String, non-null object for that key, e.g. a Boolean, Number, or nested Map/List produced by JSON deserialization of the query context.
Common situations: A client sends a context key as a JSON object/array or a number while the query path expects a string (e.g. sqlQueryId, native query ids, or string-typed context parameters); a downstream caller puts a typed object into the context map where earlier versions accepted strings; programmatic query construction setting context.put(key, someObject).
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
- Expected key [%s] to be a Boolean, but got [%s]
- Expected key [%s] to be an Integer, but got [%s]
- Expected key [%s] to be a Long, but got [%s]
- Expected key [%s] to be a Float, but got [%s]
- Expected key [%s] to be of type [%s], but got [%s]
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/c950c64e13baba37.
Report an issue: GitHub.