{"record":{"id":"ae2305f12f7fade7","repo":"sebastianbergmann/phpunit","slug":"phpt-file-must-not-contain-text-before-its-first-s","errorCode":null,"errorMessage":"PHPT file must not contain text before its first section (line %d)","messagePattern":"PHPT file must not contain text before its first section \\(line (.+?)\\)","errorType":"exception","errorClass":"InvalidPhptFileException","httpStatus":null,"severity":"error","filePath":"src/Runner/Phpt/Parser.php","lineNumber":143,"sourceCode":"\n                if (!in_array($section, self::SUPPORTED_SECTIONS, true) &&\n                    !in_array($section, self::UNSUPPORTED_SECTIONS, true) &&\n                    !in_array($section, self::IGNORED_SECTIONS, true)) {\n                    throw new UnknownPhptSectionException($section);\n                }\n\n                if (isset($sections[$section])) {\n                    throw new DuplicatePhptSectionException($section);\n                }\n\n                $sections[$section]             = '';\n                $sections[$section . '_offset'] = (string) $lineNr;\n\n                continue;\n            }\n\n            if ($section === '') {\n                throw new InvalidPhptFileException(\n                    sprintf(\n                        'PHPT file must not contain text before its first section (line %d)',\n                        $lineNr,\n                    ),\n                );\n            }\n\n            assert(isset($sections[$section]));\n\n            $sections[$section] .= $line;\n        }\n\n        $codeSection = $this->ensureExactlyOneSectionOf($sections, self::FILE_SECTIONS);\n\n        $this->ensureExactlyOneSectionOf($sections, self::EXPECTATION_SECTIONS);\n\n        if (isset($sections['FILEEOF'])) {\n            $sections['FILE'] = rtrim($sections['FILEEOF'], \"\\r\\n\");","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/sebastianbergmann/phpunit/blob/f123cdb2a2d49f15025794166cfed8bda8627dd2/src/Runner/Phpt/Parser.php#L125-L161","documentation":"parse() iterates lines before the first recognized --SECTION-- header while $section is still the empty string; any line there — a PHP open tag, a UTF-8 BOM, a shebang, a comment, or even a blank line — causes InvalidPhptFileException('PHPT file must not contain text before its first section (line N)'). A valid .phpt file must start directly with a section header, conventionally --TEST--.","triggerScenarios":"A .phpt file whose first line is '<?php', '#!/usr/bin/env php', a license comment, leading whitespace/blank lines, or a UTF-8 BOM saved by the editor; anything before the first /^--([_A-Z]+)--/ line is rejected, and the message reports the offending line number.","commonSituations":"Generating .phpt files from templates that prepend a header; editors saving with BOM; converting old tests that had a leading comment; concatenating files while building a test suite.","solutions":["Make --TEST-- (or another valid section header) the very first line of the file.","Remove leading BOM, shebang, '<?php', comments and blank lines — note that blank lines before the first header are rejected too.","Re-save the file as UTF-8 without BOM."],"exampleFix":"-- before\n<?php // example.phpt\n--TEST--\nDemo\n\n-- after\n--TEST--\nDemo","handlingStrategy":"validation","validationCode":"function assertPhptStartsWithSection(string $phptFile): void\n{\n    $lines = file($phptFile);\n\n    if ($lines === false || preg_match('/^--[_A-Z]+--/', $lines[0] ?? '') !== 1) {\n        throw new RuntimeException($phptFile . ' must start with a section header such as --TEST--');\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    $sections = (new \\PHPUnit\\Runner\\Phpt\\Parser())->parse($phptFile);\n} catch (\\PHPUnit\\Runner\\Phpt\\InvalidPhptFileException $e) {\n    if (str_contains($e->getMessage(), 'text before its first section')) {\n        // strip leading BOM/blank lines/comments so the file starts with --TEST--\n    }\n}","preventionTips":["Save .phpt files as UTF-8 without BOM.","Never put '<?php', shebangs or license comments at the top of a .phpt file; description text belongs in --TEST-- or --DESCRIPTION--.","When generating .phpt files from templates, assert the first output line is a section header."],"tags":["phpunit","phpt","file-format","bom","parser"],"backgroundTag":"malformed-file-format","analyzedSha":"f123cdb2a2d49f15025794166cfed8bda8627dd2","analyzedAt":"2026-08-23T01:20:58.058Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}