{"record":{"id":"401c3fe677ea0016","repo":"elastic/elasticsearch","slug":"test-continued-cannot-immediately-follow-te","errorCode":null,"errorMessage":"// TEST[continued] cannot immediately follow // TESTSETUP: ${test}","messagePattern":"// TEST\\[continued\\] cannot immediately follow // TESTSETUP: (.+?)","errorType":"validation","errorClass":"InvalidUserDataException","httpStatus":null,"severity":"error","filePath":"build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/doc/RestTestsFromDocSnippetTask.java","lineNumber":248,"sourceCode":"            }\n            if (snippet.test() || snippet.language().equals(\"console\")) {\n                test(snippet);\n                previousTest = snippet;\n            }\n            // Must be an unmarked snippet....\n        }\n\n        private void test(Snippet test) {\n            setupCurrent(test);\n\n            if (test.continued()) {\n                /* Catch some difficult to debug errors with // TEST[continued]\n                 * and throw a helpful error message. */\n                if (previousTest == null || previousTest.path().equals(test.path()) == false) {\n                    throw new InvalidUserDataException(\"// TEST[continued] \" + \"cannot be on first snippet in a file: \" + test);\n                }\n                if (previousTest != null && previousTest.testSetup()) {\n                    throw new InvalidUserDataException(\"// TEST[continued] \" + \"cannot immediately follow // TESTSETUP: \" + test);\n                }\n                if (previousTest != null && previousTest.testSetup()) {\n                    throw new InvalidUserDataException(\"// TEST[continued] \" + \"cannot immediately follow // TEARDOWN: \" + test);\n                }\n            } else {\n                current.println(\"---\");\n                if (test.name() != null && test.name().isBlank() == false) {\n                    if (names.add(test.name()) == false) {\n                        throw new InvalidUserDataException(\"Duplicated snippet name '\" + test.name() + \"': \" + test);\n                    }\n                    current.println(\"\\\"\" + test.name() + \"\\\":\");\n                } else {\n                    current.println(\"\\\"line_\" + test.start() + \"\\\":\");\n                }\n                /* The Elasticsearch test runner doesn't support quite a few\n                 * constructs unless we output this skip. We don't know if\n                 * we're going to use these constructs, but we might so we\n                 * output the skip just in case. */","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/doc/RestTestsFromDocSnippetTask.java#L230-L266","documentation":"Inside the test.continued() block, after verifying a same-file previousTest exists, the code checks if previousTest.testSetup() is true and throws this message. // TEST[continued] appends into the previous snippet's YAML test section, but a TESTSETUP snippet writes into the 'setup:' section — continuing from it would merge request steps into setup, which is invalid. NOTE: the source at line 247-248 checks testSetup() and labels it TESTSETUP; a near-identical check at line 250-251 (which throws the TEARDOWN message) also calls testSetup() rather than testTearDown(), which appears to be a copy-paste bug — the TEARDOWN branch likely intends to check testTearDown().","triggerScenarios":"A // TEST[continued] snippet immediately follows a // TESTSETUP snippet in the same file, so previousTest.testSetup() is true.","commonSituations":"Restructuring a doc so a TESTSETUP is the last snippet before a continued test; the continued test has no real base request to append to.","solutions":["Insert a normal (non-continued, non-setup) console request snippet between the TESTSETUP and the // TEST[continued] snippet.","Remove // TEST[continued] from the snippet if it should run as part of setup instead."],"exampleFix":"// before — continued right after setup\n// TESTSETUP\nPOST /idx/_doc\n{ \"a\": 1 }\n// CONSOLE\n// TEST[continued]\nGET /idx/_search\n\n// after — base request separates them\n// TESTSETUP\nPOST /idx/_doc\n{ \"a\": 1 }\n// CONSOLE\nGET /idx/_search\n// CONSOLE\n// TEST[continued]\nGET /idx/_search?q=a","handlingStrategy":"validation","validationCode":"// Ensure TEST[continued] does not immediately follow a TESTSETUP\nvoid checkContinuedAfterSetup(List<SnippetInfo> fileSnippets, String filePath) {\n    for (int i = 1; i < fileSnippets.size(); i++) {\n        SnippetInfo prev = fileSnippets.get(i - 1);\n        SnippetInfo cur = fileSnippets.get(i);\n        if (cur.continued && prev.testSetup) {\n            throw new IllegalStateException(\n                \"// TEST[continued] in \" + filePath + \" immediately follows TESTSETUP\");\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Separate TESTSETUP and TEST[continued] with a normal base console request.","Remember TESTSETUP writes into the 'setup:' section; a continued snippet cannot append there.","When restructuring setup snippets, re-run the docs build to catch this ordering error."],"tags":["docs","snippet","test-continued","testsetup","console"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}