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
- Move a console request snippet (// CONSOLE or [source,console]) above the response snippet in the same file.
- 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
- Always write the console request snippet before its TESTRESPONSE block.
- When splitting a doc file, move each request+response pair together.
- Treat a TESTRESPONSE with no preceding request in the same file as a lint error.
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
- ${snippet}: Result can't be first in file
- // TEST[continued] cannot immediately follow // TESTSETUP: $
- ${snippet}: wasn't first. TESTSETUP can only be used in the
- Extra content ${message} ('${cutOutNoNl}') matching [${patte
- Didn't match ${pattern}: ${content}
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/d568ab76ef4a9264.
Report an issue: GitHub.