thanos-io/thanos · error · api.ApiError
Query not explainable
Error message
Query not explainable
What it means
getQueryExplain returns an HTTP 400 (api.ErrorBadData) when the promql.Query object returned by the engine does not implement engine.ExplainableQuery, so Explain() cannot be called. This happens when the query was executed by an engine whose query type lacks explain support (e.g. the plain Prometheus engine instead of the Thanos engine).
Solutions
- Pass `engine=thanos` in the request so the query runs on the explainable Thanos engine.
- Upgrade Thanos to a version where the Thanos engine supports Explain on all query paths.
- Remove explain calls from clients when using the Prometheus engine, since it does not support explain.
Example fix
// before GET /api/v1/query_explain?query=up&engine=prometheus // after GET /api/v1/query_explain?query=up&engine=thanos
Defensive patterns
Strategy: try-catch
Validate before calling
if (engine && engine !== 'thanos') {
throw new Error('query_explain requires engine=thanos');
} Try / catch
const body = await res.json();
if (body.status === 'error' && body.error === 'Query not explainable') {
// fall back to a normal query without explain, or switch engine=thanos
} Prevention
- Only call explain endpoints against Thanos-engine deployments.
- Always send engine=thanos explicitly with explain requests.
- Check your Thanos version supports ExplainableQuery before relying on explain.
When it happens
Trigger: Calling the query_explain endpoint (queryExplain/queryRangeExplain) while the effective engine is not the Thanos engine, so the returned query cannot be type-asserted to engine.ExplainableQuery.
Common situations: Older Thanos builds or deployments where the promql engine fallback is active; clients hitting explain endpoints after the engine was switched to 'prometheus'.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Query: not analyzable
- Query fallback to prometheus engine; not analyzable.
- Query not analyzable; change engine to 'thanos'.
- at modifier after end
- negative offset
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/2768efa9e0818fff.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/api/query/v1.go:438
}
if len(data) == 0 {
return nil, nil
}
var info storepb.ShardInfo
if err := json.Unmarshal([]byte(data), &info); err != nil {
return nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.Wrapf(err, "could not unmarshal parameter %s", ShardInfoParam)}
}
return &info, nil
}
func (qapi *QueryAPI) getQueryExplain(query promql.Query) (*engine.ExplainOutputNode, *api.ApiError) {
if eq, ok := query.(engine.ExplainableQuery); ok {
return eq.Explain(), nil
}
return nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.Errorf("Query not explainable")}
}
func (qapi *QueryAPI) parseQueryAnalyzeParam(r *http.Request) bool {
return (r.FormValue(QueryAnalyzeParam) == "true" || r.FormValue(QueryAnalyzeParam) == "1")
}
func analyzeQueryOutput(query promql.Query, engineType PromqlEngineType, tracker *fanout.Tracker) (queryTelemetry, error) {
if eq, ok := query.(engine.ExplainableQuery); ok {
if analyze := eq.Analyze(); analyze != nil {
return processAnalysis(analyze, tracker), nil
} else {
return queryTelemetry{}, errors.Errorf("Query: %v not analyzable", query)
}
}
var warning error
if engineType == PromqlEngineThanos {
warning = errors.New("Query fallback to prometheus engine; not analyzable.")View on GitHub (pinned to 35b8b99117)