apache/druid · error · BadQueryContextException
Timeout [timeout] must be a non negative value, but was %d
Error message
Timeout [timeout] must be a non negative value, but was %d
What it means
Druid validates the `timeout` query-context key before using it. If the caller supplies a negative long for the timeout (in milliseconds), QueryContext.getTimeout refuses to return it and throws BadQueryContextException. This guard exists because a negative timeout is meaningless and would corrupt the query deadline computation in QueryContexts/ChainedExecutionQueryRunner.
Source
Thrown at processing/src/main/java/org/apache/druid/query/QueryContext.java:508
}
public boolean hasTimeout()
{
return getTimeout() != QueryContexts.NO_TIMEOUT;
}
public long getTimeout()
{
return getTimeout(getDefaultTimeout());
}
public long getTimeout(long defaultTimeout)
{
final long timeout = getLong(QueryContexts.TIMEOUT_KEY, defaultTimeout);
if (timeout >= 0) {
return timeout;
}
throw new BadQueryContextException(
StringUtils.format(
"Timeout [%s] must be a non negative value, but was %d",
QueryContexts.TIMEOUT_KEY,
timeout
)
);
}
@Nullable
public Duration getTimeoutDuration()
{
if (hasTimeout()) {
return Duration.ofMillis(getTimeout());
}
return null;
}
public long getDefaultTimeout()View on GitHub (pinned to 9b90983fd2)
Solutions
- Inspect the query's `context` object and set `timeout` to a non-negative millisecond value, or remove the key to use the default timeout.
- If the timeout is computed at runtime, clamp it: `long t = Math.max(0, deadline - now);`
- Check the calling client/library for integer underflow or sign errors when deriving the timeout.
- Catch BadQueryContextException in the query-submitting code and surface a clear client-side validation message before sending the query.
Example fix
// before
context.put("timeout", deadlineMillis - System.currentTimeMillis()); // can be negative
// after
long timeout = Math.max(0, deadlineMillis - System.currentTimeMillis());
context.put("timeout", timeout); Defensive patterns
Strategy: validation
Validate before calling
Object timeout = query.getContext().get("timeout");
if (timeout instanceof Number && ((Number) timeout).longValue() < 0) {
throw new IllegalArgumentException("timeout must be non-negative, got " + timeout);
} Type guard
boolean isValidTimeout(Object v) {
return !(v instanceof Number) || ((Number) v).longValue() >= 0;
} Try / catch
try {
client.query(query);
} catch (DruidException | BadQueryContextException e) {
if (e.getMessage().contains("must be a non negative value")) {
query.getContext().remove("timeout"); // fall back to default
client.query(query);
} else {
throw e;
}
} Prevention
- Never put negative sentinel values (e.g. -1) in query context; omit the key for defaults.
- Clamp computed timeouts with Math.max(0, value) before submission.
- Validate query context in your query-builder layer before sending.
- Unit-test query builders with edge-case deadline arithmetic to catch underflow.
When it happens
Trigger: Calling QueryContext.getTimeout(long defaultTimeout) (directly or via timeout()) when the query context map contains TIMEOUT_KEY ("timeout") with a value < 0, e.g. `{"timeout": -5000}` supplied by a client in the query request's context object.
Common situations: Client SDKs or dashboard tools computing a remaining budget as an int that underflowed or was computed from a past deadline; hand-written JSON query payloads with negative timeouts; programmatic query builders subtracting timestamps in the wrong order.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Per-segment timeout [timeoutPerSegmentQuery] must be a non n
- Timeout [maxDefaultTimeout] must be a non negative value, bu
- Query [%s] timed out
- Expected key [%s] to be referring to one of the values [%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/4914d228cfe66e39.
Report an issue: GitHub.