sebastianbergmann/phpunit · error · DuplicatePhptSectionException

--%s-- section occurs more than once

Error message

--%s-- section occurs more than once

What it means

In the same line scan, once a section header passes the known-section check, the parser checks isset($sections[$section]); if the same header appears twice anywhere in the file, DuplicatePhptSectionException('--%s-- section occurs more than once') is thrown. Each real section must be unique — section content is not concatenated across occurrences.

Source

Thrown at src/Runner/Phpt/Parser.php:133

            throw new CannotLoadPhptFileException;
        }

        $lineNr = 0;

        foreach ($lines as $line) {
            $lineNr++;

            if (preg_match('/^--([_A-Z]+)--/', $line, $result) === 1) {
                $section = $result[1];

                if (!in_array($section, self::SUPPORTED_SECTIONS, true) &&
                    !in_array($section, self::UNSUPPORTED_SECTIONS, true) &&
                    !in_array($section, self::IGNORED_SECTIONS, true)) {
                    throw new UnknownPhptSectionException($section);
                }

                if (isset($sections[$section])) {
                    throw new DuplicatePhptSectionException($section);
                }

                $sections[$section]             = '';
                $sections[$section . '_offset'] = (string) $lineNr;

                continue;
            }

            if ($section === '') {
                throw new InvalidPhptFileException(
                    sprintf(
                        'PHPT file must not contain text before its first section (line %d)',
                        $lineNr,
                    ),
                );
            }

            assert(isset($sections[$section]));

View on GitHub (pinned to f123cdb2a2)

Solutions

  1. Delete the duplicate so each section header appears exactly once.
  2. When merging content (for example two INI blocks), combine the settings into a single section.
  3. If you need two variants of the same test, split them into two separate .phpt files.

Example fix

-- before
--EXPECT--
Hello
--EXPECT--
Hello World

-- after
--EXPECT--
Hello World
Defensive patterns

Strategy: validation

Validate before calling

function assertNoDuplicatePhptSections(string $phptFile): void
{
    $seen = [];

    foreach (file($phptFile) as $i => $line) {
        if (preg_match('/^--([_A-Z]+)--/', $line, $m) === 1) {
            if (isset($seen[$m[1]])) {
                throw new RuntimeException(sprintf('Duplicate section --%s-- at line %d', $m[1], $i + 1));
            }
            $seen[$m[1]] = true;
        }
    }
}

Try / catch

try {
    $sections = (new \PHPUnit\Runner\Phpt\Parser())->parse($phptFile);
} catch (\PHPUnit\Runner\Phpt\DuplicatePhptSectionException $e) {
    // $e->getMessage() names the duplicated section; fix the file and retry
}

Prevention

When it happens

Trigger: A .phpt file with two --EXPECT-- blocks, two --FILE-- sections, or duplicated --INI--/--ENV-- blocks where the author intended settings to accumulate or merge.

Common situations: Merging or copy-pasting PHPT tests; appending an updated expectation at the bottom instead of replacing the old one; splitting a test into variants and forgetting to delete the original section.

Related errors


AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23). Data as JSON: /api/errors/feb5e78afb170ea6. Report an issue: GitHub.