elastic/elasticsearch · error · IllegalArgumentException
Unknown key for a VALUE_STRING in [project_routing]
Error message
Unknown key for a VALUE_STRING in [project_routing]
What it means
Thrown by the single _search/template REST handler when the request body includes a top-level 'project_routing' field but the cluster's cross-project search feature flag (crossProjectEnabled) is off. The field is only honored when the node is configured to allow cross-project routing; otherwise it is rejected as an unknown key rather than silently ignored.
Source
Thrown at modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/RestSearchTemplateAction.java:90
request,
null,
clusterSupportsFeature,
size -> searchRequest.source().size(size),
null,
Optional.of(crossProjectEnabled)
);
// Creates the search template request
SearchTemplateRequest searchTemplateRequest;
try (XContentParser parser = request.contentOrSourceParamParser()) {
searchTemplateRequest = SearchTemplateRequest.fromXContent(parser);
}
if (searchTemplateRequest.getProjectRouting() != null) {
if (crossProjectEnabled) {
searchRequest.setProjectRouting(searchTemplateRequest.getProjectRouting());
} else {
throw new IllegalArgumentException("Unknown key for a VALUE_STRING in [project_routing]");
}
}
searchTemplateRequest.setRequest(searchRequest);
// This param is parsed within the search request
if (searchRequest.source().explain() != null) {
searchTemplateRequest.setExplain(searchRequest.source().explain());
}
return channel -> client.execute(
MustachePlugin.SEARCH_TEMPLATE_ACTION,
searchTemplateRequest,
new RestRefCountedChunkedToXContentListener<>(channel) {
@Override
protected RestStatus getRestStatus(SearchTemplateResponse searchTemplateResponse) {
return searchTemplateResponse.status();
}
}
);View on GitHub (pinned to db6a809a66)
Solutions
- Remove the 'project_routing' key from the request body if cross-project routing is not needed.
- Enable the cross-project search feature on the cluster (set the governing node-level setting) and restart, if the deployment genuinely needs cross-project routing.
- Verify the Elasticsearch version supports this field and that the feature flag is actually toggled on via the cluster's settings API before sending.
- If routing is the intent, use the standard 'routing' parameter on the search request instead of 'project_routing'.
Example fix
// before
POST /_search/template
{ "id": "t", "params": {}, "project_routing": "projA" }
// after (cross-project disabled)
POST /_search/template
{ "id": "t", "params": {} } Defensive patterns
Strategy: validation
Validate before calling
// Check feature availability before sending project_routing
async function canCrossProject(client) {
// Probe cluster settings / feature flag relevant to your deployment
const info = await client.info();
// Heuristic: only attach project_routing when the deployment advertises cross-project support
return Boolean(info.features && info.features.cross_project);
}
// then: if (!(await canCrossProject(client))) delete body.project_routing; Try / catch
// ElasticsearchStatusException e -> if (e.getMessage().contains('project_routing')) { /* remove field and retry once */ } Prevention
- Gate client-side code that adds project_routing behind a feature check.
- Document the cluster version/flag requirement next to any code using project_routing.
- Prefer the standard 'routing' parameter unless cross-project semantics are required.
When it happens
Trigger: POST to _search/template (or _msearch/template) with a JSON body containing "project_routing": "value" while the controlling setting/flag for cross-project search is false (default). The handler checks searchTemplateRequest.getProjectRouting() != null && !crossProjectEnabled and throws.
Common situations: Enabling a feature in a client library or UI that targets a newer Elasticsearch version than the deployed cluster. Sending requests meant for a stateless/cross-project deployment to a standard cluster. Misreading docs that describe project_routing without noting the feature flag dependency.
Related errors
- Malformed search template
- project_routing already set
- Could not parse inline template
- [rest_total_hits_as_int] cannot be used if the tracking of t
- Unknown REST API version {}
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/b2d99fb592373528.
Report an issue: GitHub.