elastic/elasticsearch · error · InvalidUserDataException

${snippet}: No paired previous test

Error message

${snippet}: No paired previous test

What it means

When a snippet is a test response (snippet.testResponse() true or language 'console-result'), handleSnippet expects a preceding non-response snippet (previousTest) to pair it with. previousTest is null only at the very start of the build before any test/setup/teardown snippet was seen. A response with no prior request has nothing to match against, so it throws.

Source

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

            if (snippet.isConsoleCandidate()) {
                unconvertedCandidates.add(snippet.path().toString().replace('\\', '/'));
            }
            if (BAD_LANGUAGES.contains(snippet.language())) {
                throw new InvalidUserDataException(snippet + ": Use `js` instead of `" + snippet.language() + "`.");
            }
            if (snippet.testSetup()) {
                testSetup(snippet);
                previousTest = snippet;
                return;
            }
            if (snippet.testTearDown()) {
                testTearDown(snippet);
                previousTest = snippet;
                return;
            }
            if (snippet.testResponse() || snippet.language().equals("console-result")) {
                if (previousTest == null) {
                    throw new InvalidUserDataException(snippet + ": No paired previous test");
                }
                if (previousTest.path().equals(snippet.path()) == false) {
                    throw new InvalidUserDataException(snippet + ": Result can't be first in file");
                }
                response(snippet);
                return;
            }
            if (("js".equals(snippet.language())) && snippet.console() != null && snippet.console()) {
                throw new InvalidUserDataException(snippet + ": Use `[source,console]` instead of `// CONSOLE`.");
            }
            if (snippet.test() || snippet.language().equals("console")) {
                test(snippet);
                previousTest = snippet;
            }
            // Must be an unmarked snippet....
        }

        private void test(Snippet test) {

View on GitHub (pinned to db6a809a66)

Solutions

  1. Move a console request snippet (// CONSOLE or [source,console]) above the response snippet in the same file.
  2. If the response is orphaned, remove it or reattach it to its original request snippet.

Example fix

// before — response with no preceding request
// TESTRESPONSE
{"acknowledged":true}

// after — add the request first
// CONSOLE
POST /_aliases
{ "actions": [] }
// TESTRESPONSE
{"acknowledged":true}
Defensive patterns

Strategy: validation

Validate before calling

// Ensure every TESTRESPONSE/console-result snippet has a preceding request in the same doc
// (run as a pre-build docs lint over parsed snippets)
void checkResponsesPaired(List<SnippetInfo> snippets) {
    boolean seenRequest = false;
    for (SnippetInfo s : snippets) {
        if (s.isResponse) {
            if (!seenRequest) {
                throw new IllegalStateException(
                    "Response snippet " + s.path + " has no preceding request");
            }
        } else if (s.isRequest) {
            seenRequest = true;
        }
    }
}

Prevention

When it happens

Trigger: A document file's first snippet is a console-result / TESTRESPONSE block, or a TESTRESPONSE appears after a previous test that was in a different file and was not carried over — actually this specific branch (previousTest == null) fires only when no test snippet has been seen at all across the entire run up to this point.

Common situations: Reordering snippets in a doc file so a response block lands at the top, or splitting a file and leaving the response in the new file without its request. The more common cross-file case is caught by the separate 'Result can't be first in file' check.

Related errors


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