apache/druid · error · BadQueryContextException
Configured timeout =
Error message
Configured timeout = %d is more than enforced limit of %d.
What it means
Druid allows operators to enforce a maximum query timeout (maxQueryTimeout, e.g. via druid.query.scheduler or server config). QueryContext.verifyMaxQueryTimeout compares the effective `timeout` in the query context against that enforced limit and throws BadQueryContextException when the caller asks for more timeout than the server permits. This is a server-side resource-protection guard, not a type or format error.
Solutions
- Lower the query's `timeout` context value to at or below the enforced limit reported in the message.
- If the larger timeout is legitimate, have the operator raise the enforced maxQueryTimeout server-side.
- Make clients discover the limit (config/endpoint) and clamp their requested timeout before submitting.
- Catch BadQueryContextException and surface the 'enforced limit of %d' value to the user so they can adjust.
Example fix
// before
context.put("timeout", 600_000L); // exceeds server limit of 300_000
// after
long requested = 600_000L;
long limit = 300_000L; // obtained from server config
context.put("timeout", Math.min(requested, limit)); Defensive patterns
Strategy: validation
Validate before calling
long requested = ((Number) query.getContext().getOrDefault("timeout", 0L)).longValue();
long enforcedLimit = /* from broker config */ 300_000L;
if (requested > enforcedLimit) {
query.getContext().put("timeout", enforcedLimit);
} Type guard
boolean withinTimeoutLimit(Object v, long limit) {
return !(v instanceof Number) || ((Number) v).longValue() <= limit;
} Try / catch
try {
client.query(query);
} catch (BadQueryContextException e) {
if (e.getMessage().contains("enforced limit of")) {
long limit = parseEnforcedLimit(e.getMessage());
query.getContext().put("timeout", limit);
client.query(query);
} else {
throw e;
}
} Prevention
- Discover the server's enforced max timeout and clamp client requests to it.
- Avoid hard-coding large timeouts in dashboards/tools; make them configurable.
- Coordinate with operators when the enforced limit changes.
- Prefer query optimization over raising timeout caps.
When it happens
Trigger: Calling QueryContext.verifyMaxQueryTimeout(long maxQueryTimeout) when the context's `timeout` value exceeds the enforced limit, e.g. context has `{"timeout": 600000}` (10 min) while the server enforces max 300000 ms (5 min).
Common situations: Clients migrating from an unenforced cluster to one with a max-query-timeout cap; dashboards with hard-coded long timeouts; operators lowering the enforced limit without notifying query clients.
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…
- Query [ ] timed out
- Timeout [maxDefaultTimeout] must be a non negative value…
- Timeout [timeout] must be a non negative value, but was
- Cache for node role [ ] could not be initialized before…
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/e014c5d574ce027a.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/query/QueryContext.java:545
{
final long defaultTimeout = getLong(QueryContexts.DEFAULT_TIMEOUT_KEY, QueryContexts.DEFAULT_TIMEOUT_MILLIS);
if (defaultTimeout >= 0) {
return defaultTimeout;
}
throw new BadQueryContextException(
StringUtils.format(
"Timeout [%s] must be a non negative value, but was %d",
QueryContexts.DEFAULT_TIMEOUT_KEY,
defaultTimeout
)
);
}
public void verifyMaxQueryTimeout(long maxQueryTimeout)
{
long timeout = getTimeout();
if (timeout > maxQueryTimeout) {
throw new BadQueryContextException(
StringUtils.format(
"Configured %s = %d is more than enforced limit of %d.",
QueryContexts.TIMEOUT_KEY,
timeout,
maxQueryTimeout
)
);
}
}
public long getPerSegmentTimeout()
{
return getPerSegmentTimeout(QueryContexts.NO_TIMEOUT);
}
public long getPerSegmentTimeout(long defaultPerSegmentTimeout)
{
final long timeout = getLong(QueryContexts.PER_SEGMENT_TIMEOUT_KEY, defaultPerSegmentTimeout);View on GitHub (pinned to 9b90983fd2)