elastic/elasticsearch · error · IllegalArgumentException

[painless.regex.limit-factor] can only be set on node startu

Error message

[painless.regex.limit-factor] can only be set on node startup.

What it means

PainlessScriptEngine.buildCompilerSettings throws this IllegalArgumentException when a per-script compile parameter includes 'painless.regex.limit-factor'. This setting caps regex complexity (the automaton state expansion factor) and is a node-level security control; it cannot be tuned per request. Like regex.enabled, it is only read from the node's context defaults at startup.

Source

Thrown at modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngine.java:449

            value = copy.remove(CompilerSettings.PICKY);
            if (value != null) {
                compilerSettings.setPicky(Booleans.parseBoolean(value));
            }

            value = copy.remove(CompilerSettings.INITIAL_CALL_SITE_DEPTH);
            if (value != null) {
                compilerSettings.setInitialCallSiteDepth(Integer.parseInt(value));
            }

            value = copy.remove(CompilerSettings.REGEX_ENABLED.getKey());
            if (value != null) {
                throw new IllegalArgumentException("[painless.regex.enabled] can only be set on node startup.");
            }

            value = copy.remove(CompilerSettings.REGEX_LIMIT_FACTOR.getKey());
            if (value != null) {
                throw new IllegalArgumentException("[painless.regex.limit-factor] can only be set on node startup.");
            }

            if (copy.isEmpty() == false) {
                throw new IllegalArgumentException("Unrecognized compile-time parameter(s): " + copy);
            }
        }
        return compilerSettings;
    }

    private static ScriptException convertToScriptException(String scriptSource, Throwable t) {
        // create a script stack: this is just the script portion
        List<String> scriptStack = new ArrayList<>();
        ScriptException.Position pos = null;
        for (StackTraceElement element : t.getStackTrace()) {
            if (WriterConstants.CLASS_NAME.equals(element.getClassName())) {
                // found the script portion
                int originalOffset = element.getLineNumber();
                if (originalOffset == -1) {

View on GitHub (pinned to db6a809a66)

Solutions

  1. Set script.painless.regex.limit-factor in elasticsearch.yml or via the cluster settings API, then restart/reload.
  2. Remove the key from the script's params map.
  3. If regexes are hitting the limit, simplify the regex pattern rather than tuning the limit per-script.

Example fix

// before (script params)
{"source": "...", "params": {"painless.regex.limit-factor": 50}}
// after (elasticsearch.yml)
script.painless.regex.limit-factor: 50
Defensive patterns

Strategy: validation

Validate before calling

// Do not include painless.regex.limit-factor in script params. Set it at node level:
// // elasticsearch.yml: script.painless.regex.limit-factor: 50

Prevention

When it happens

Trigger: Submitting a script with params containing {'painless.regex.limit-factor': '100'} in any compilation context (ingest, search, runtime fields). The buildCompilerSettings method detects the key in the params copy and rejects it.

Common situations: Attempting to raise or lower the regex complexity limit per-query to work around a regex timeout. Confusing node settings with script params. Porting configuration between environments.

Related errors


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