{"record":{"id":"40923c8b285fa262","repo":"elastic/elasticsearch","slug":"invalid-json-in-name-the-error-is-errormessag","errorCode":null,"errorMessage":"Invalid json in {name}. The error is:\n{errorMessage}.\nAfter substitutions and munging, the json looks like:\n{quoted}","messagePattern":"Invalid json in (.+?)\\. The error is:\n(.+?)\\.\nAfter substitutions and munging, the json looks like:\n(.+?)","errorType":"validation","errorClass":"InvalidUserDataException","httpStatus":null,"severity":"error","filePath":"build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/doc/SnippetBuilder.java","lineNumber":249,"sourceCode":"    private void assertValidJsonInput(String content) {\n        if (testResponse && (\"js\" == language || \"console-result\" == language) && null == skip) {\n            String quoted = content\n                // quote values starting with $\n                .replaceAll(\"([:,])\\\\s*(\\\\$[^ ,\\\\n}]+)\", \"$1 \\\"$2\\\"\")\n                // quote fields starting with $\n                .replaceAll(\"(\\\\$[^ ,\\\\n}]+)\\\\s*:\", \"\\\"$1\\\":\");\n\n            JsonFactory jf = new JsonFactory();\n            jf.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true);\n            JsonParser jsonParser;\n\n            try {\n                jsonParser = jf.createParser(quoted);\n                while (jsonParser.isClosed() == false) {\n                    jsonParser.nextToken();\n                }\n            } catch (JsonParseException e) {\n                throw new InvalidUserDataException(\n                    \"Invalid json in \"\n                        + name\n                        + \". The error is:\\n\"\n                        + e.getMessage()\n                        + \".\\n\"\n                        + \"After substitutions and munging, the json looks like:\\n\"\n                        + quoted,\n                    e\n                );\n            } catch (IOException e) {\n                throw new RuntimeException(e);\n            }\n        }\n    }\n\n    public SnippetBuilder withConsole(Boolean console) {\n        this.console = console;\n        return this;","sourceCodeStart":231,"sourceCodeEnd":267,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/doc/SnippetBuilder.java#L231-L267","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Copy the 'After substitutions and munging' JSON from the error message and paste it into a JSON linter to find the exact syntax error.","Fix the source snippet so the post-substitution result is valid JSON (balance braces, remove trailing commas, quote non-`$` keys).","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).","For genuinely non-JSON content use the `non_json` TESTRESPONSE modifier instead of trying to make it parse."],"exampleFix":"// before:\n// TESTRESPONSE\n{ \"hits\": { \"total\": 42, } }  // trailing comma\n// after:\n// TESTRESPONSE\n{ \"hits\": { \"total\": 42 } }","handlingStrategy":"try-catch","validationCode":"// Before building, run the snippet's post-substitution JSON through a parser:\n// String quoted = applySubstitutions(content); JsonParser p = jf.createParser(quoted);\n// while (!p.isClosed()) p.nextToken();  // throws on invalid JSON","typeGuard":null,"tryCatchPattern":"// try (JsonParser p = jf.createParser(quoted)) { while (!p.isClosed()) p.nextToken(); }\n// catch (JsonParseException e) { /* report snippet name + quoted text + e.getMessage() */ }","preventionTips":["Validate every TESTRESPONSE snippet's JSON in a linter before committing.","Place `$variable` placeholders at value/field boundaries the auto-quoting regex expects.","Use the `non_json` TESTRESPONSE modifier for genuinely non-JSON responses instead of fighting the parser.","Avoid trailing commas and unquoted non-`$` keys."],"tags":["docs","snippet-tests","json","validation"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}