elastic/elasticsearch · error · InvalidUserDataException

Invalid json in {name}. The error is: {errorMessage}. After

Error message

Invalid json in {name}. The error is:
{errorMessage}.
After substitutions and munging, the json looks like:
{quoted}

What it means

Thrown by SnippetBuilder.assertValidJsonInput() when a snippet marked for response testing (TESTRESPONSE) in `js` or `console-result` language fails to parse as JSON after the doc framework applies its variable substitution/munging. The framework quotes `$`-prefixed values and fields, enables lenient backslash escaping, then runs the Jackson parser end-to-end; a JsonParseException is rethrown with the original parser message plus the post-substitution text so the author can see exactly what failed.

Source

Thrown at build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/doc/SnippetBuilder.java:249

    private void assertValidJsonInput(String content) {
        if (testResponse && ("js" == language || "console-result" == language) && null == skip) {
            String quoted = content
                // quote values starting with $
                .replaceAll("([:,])\\s*(\\$[^ ,\\n}]+)", "$1 \"$2\"")
                // quote fields starting with $
                .replaceAll("(\\$[^ ,\\n}]+)\\s*:", "\"$1\":");

            JsonFactory jf = new JsonFactory();
            jf.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true);
            JsonParser jsonParser;

            try {
                jsonParser = jf.createParser(quoted);
                while (jsonParser.isClosed() == false) {
                    jsonParser.nextToken();
                }
            } catch (JsonParseException e) {
                throw new InvalidUserDataException(
                    "Invalid json in "
                        + name
                        + ". The error is:\n"
                        + e.getMessage()
                        + ".\n"
                        + "After substitutions and munging, the json looks like:\n"
                        + quoted,
                    e
                );
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public SnippetBuilder withConsole(Boolean console) {
        this.console = console;
        return this;

View on GitHub (pinned to db6a809a66)

Solutions

  1. Copy the 'After substitutions and munging' JSON from the error message and paste it into a JSON linter to find the exact syntax error.
  2. Fix the source snippet so the post-substitution result is valid JSON (balance braces, remove trailing commas, quote non-`$` keys).
  3. If the failure is a substitution artifact, adjust how the `$variable` is placed so the auto-quoting regex matches it (it expects `$`-tokens at value or field positions, not embedded inside other tokens).
  4. For genuinely non-JSON content use the `non_json` TESTRESPONSE modifier instead of trying to make it parse.

Example fix

// before:
// TESTRESPONSE
{ "hits": { "total": 42, } }  // trailing comma
// after:
// TESTRESPONSE
{ "hits": { "total": 42 } }
Defensive patterns

Strategy: try-catch

Validate before calling

// Before building, run the snippet's post-substitution JSON through a parser:
// String quoted = applySubstitutions(content); JsonParser p = jf.createParser(quoted);
// while (!p.isClosed()) p.nextToken();  // throws on invalid JSON

Try / catch

// try (JsonParser p = jf.createParser(quoted)) { while (!p.isClosed()) p.nextToken(); }
// catch (JsonParseException e) { /* report snippet name + quoted text + e.getMessage() */ }

Prevention

When it happens

Trigger: A `// TESTRESPONSE` snippet in js/console-result contains JSON that is malformed even after the framework's `$variable` quoting substitutions. Triggers on: unbalanced braces/brackets, trailing commas, unquoted keys (other than `$`-prefixed ones the regex handles), invalid escape sequences beyond the lenient mode, or a substitution that produces invalid JSON.

Common situations: A response example has a hand-edited typo; a `$variable` placeholder is placed where the auto-quoting regex does not apply (e.g. mid-token rather than at a value/field boundary); the snippet was converted from a non-JSON format and kept invalid syntax; an escape like `\x` that Jackson's ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER still rejects.

Understand the failure class

Related errors


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