elastic/elasticsearch · error · IllegalArgumentException

project_routing already set

Error message

project_routing already set

What it means

SearchTemplateRequest.setProjectRouting rejects a second assignment: if the field is already non-null it throws immediately. During XContent parsing the field is declared once via PARSER.declareString(...PROJECT_ROUTING_FIELD), so a duplicate 'project_routing' key in the same JSON object triggers the setter twice and this error.

Source

Thrown at modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/SearchTemplateRequest.java:155

    public String getScript() {
        return script;
    }

    public void setScript(String script) {
        this.script = script;
    }

    public Map<String, Object> getScriptParams() {
        return scriptParams;
    }

    public void setScriptParams(Map<String, Object> scriptParams) {
        this.scriptParams = scriptParams;
    }

    public void setProjectRouting(@Nullable String projectRouting) {
        if (this.projectRouting != null) {
            throw new IllegalArgumentException("project_routing already set");
        }

        this.projectRouting = projectRouting;
    }

    @Nullable
    public String getProjectRouting() {
        return projectRouting;
    }

    @Override
    public ActionRequestValidationException validate() {
        ActionRequestValidationException validationException = null;
        if (script == null || script.isEmpty()) {
            validationException = addValidationError("template is missing", validationException);
        }
        if (scriptType == null) {
            validationException = addValidationError("template's script type is missing", validationException);

View on GitHub (pinned to db6a809a66)

Solutions

  1. Dedupe the request body: ensure 'project_routing' appears at most once per SearchTemplateRequest JSON object.
  2. In client code, check request.getProjectRouting() == null before calling setProjectRouting, or overwrite the raw field rather than using the guarded setter.
  3. Validate the serialized JSON with a strict parser/schema that rejects duplicate keys before sending.

Example fix

// before
{"id":"t","project_routing":"a","params":{},"project_routing":"b"}
// after
{"id":"t","project_routing":"a","params":{}}
Defensive patterns

Strategy: validation

Validate before calling

// Reject duplicate keys in JSON before sending
function assertNoDuplicateKeys(jsonText) {
  JSON.parse(jsonText, (key, value, ctx) => {
    // Strict parsers throw on duplicates; alternatively pre-scan raw text
    return value;
  });
  // Robust: count occurrences
  const seen = {};
  for (const m of jsonText.matchAll(/"([a-zA-Z_][a-zA-Z0-9_]*)"\s*:/g)) {
    seen[m[1]] = (seen[m[1]] || 0) + 1;
    if (seen[m[1]] > 1) throw new Error(`Duplicate key '${m[1]}' would trigger server-side guard`);
  }
}

Prevention

When it happens

Trigger: A _search/template or _msearch/template request body where 'project_routing' appears more than once at the same object level, e.g. {"project_routing":"a", ..., "project_routing":"b"}. Also reachable if application code calls setProjectRouting twice on the same request instance before sending.

Common situations: JSON merge logic that unions two request fragments each carrying project_routing. Templating code that injects the field unconditionally then a caller adds it again. Client-side request builders that set defaults and then overlay user input without checking.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/50af17a6a99e0fa2. Report an issue: GitHub.