elastic/elasticsearch · error · InvalidUserDataException
// TEST[continued] cannot immediately follow // TEARDOWN: ${
Error message
// TEST[continued] cannot immediately follow // TEARDOWN: ${test} What it means
This is the third guard inside test.continued(). The source at lines 250-251 checks 'previousTest != null && previousTest.testSetup()' but the message says 'cannot immediately follow // TEARDOWN'. This is a suspected copy-paste defect: the condition likely should call previousTest.testTearDown() to detect a continued snippet following a teardown. As written, it fires under the same condition as the TESTSETUP message (previousTest is a setup), so the TEARDOWN label is misleading. A continued snippet is invalid after a teardown because teardowns close out a test section.
Source
Thrown at build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/doc/RestTestsFromDocSnippetTask.java:251
previousTest = snippet;
}
// Must be an unmarked snippet....
}
private void test(Snippet test) {
setupCurrent(test);
if (test.continued()) {
/* Catch some difficult to debug errors with // TEST[continued]
* and throw a helpful error message. */
if (previousTest == null || previousTest.path().equals(test.path()) == false) {
throw new InvalidUserDataException("// TEST[continued] " + "cannot be on first snippet in a file: " + test);
}
if (previousTest != null && previousTest.testSetup()) {
throw new InvalidUserDataException("// TEST[continued] " + "cannot immediately follow // TESTSETUP: " + test);
}
if (previousTest != null && previousTest.testSetup()) {
throw new InvalidUserDataException("// TEST[continued] " + "cannot immediately follow // TEARDOWN: " + test);
}
} else {
current.println("---");
if (test.name() != null && test.name().isBlank() == false) {
if (names.add(test.name()) == false) {
throw new InvalidUserDataException("Duplicated snippet name '" + test.name() + "': " + test);
}
current.println("\"" + test.name() + "\":");
} else {
current.println("\"line_" + test.start() + "\":");
}
/* The Elasticsearch test runner doesn't support quite a few
* constructs unless we output this skip. We don't know if
* we're going to use these constructs, but we might so we
* output the skip just in case. */
current.println(" - skip:");
current.println(" features:");
current.println(" - default_shards");View on GitHub (pinned to db6a809a66)
Solutions
- Add a new base console request snippet between the teardown and the // TEST[continued] snippet.
- Remove // TEST[continued] if the snippet should stand alone as a new test.
- If you maintain build-tools-internal, consider fixing the condition at line 250 to call testTearDown() so the message matches its true trigger.
Example fix
// before — continued after teardown
// TEARDOWN
DELETE /idx
// CONSOLE
// TEST[continued]
GET /idx/_search
// after — new base request first
// TEARDOWN
DELETE /idx
// CONSOLE
POST /idx2/_doc
{ "a": 1 }
// CONSOLE
// TEST[continued]
GET /idx2/_search Defensive patterns
Strategy: validation
Validate before calling
// Ensure TEST[continued] does not immediately follow a TEARDOWN (intent of the guard)
// NOTE: source code at line 250 checks testSetup() rather than testTearDown();
// this lint checks the intended condition.
void checkContinuedAfterTeardown(List<SnippetInfo> fileSnippets, String filePath) {
for (int i = 1; i < fileSnippets.size(); i++) {
SnippetInfo prev = fileSnippets.get(i - 1);
SnippetInfo cur = fileSnippets.get(i);
if (cur.continued && prev.testTearDown) {
throw new IllegalStateException(
"// TEST[continued] in " + filePath + " immediately follows TEARDOWN");
}
}
} Prevention
- Never place // TEST[continued] directly after a teardown snippet; insert a new base request first.
- If you maintain build-tools-internal, consider fixing line 250 to call testTearDown() so the message matches its trigger.
- Treat teardown as closing a test section — nothing can continue from it.
When it happens
Trigger: Per current code: identical trigger to the TESTSETUP message (previousTest is a setup). Per intent: a // TEST[continued] snippet immediately follows a // TEARDOWN snippet in the same file.
Common situations: Reordering snippets so a teardown is followed by a continued test; the continued block has no open test section to append to after a teardown closed it.
Related errors
- // TEST[continued] cannot be on first snippet in a file: ${t
- // TEST[continued] cannot immediately follow // TESTSETUP: $
- Extra content ${message} ('${cutOutNoNl}') matching [${patte
- Didn't match ${pattern}: ${content}
- Invalid block quote starting at ${start} in: ${body}
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/b8de672e73e920d3.
Report an issue: GitHub.