sebastianbergmann/phpunit · error · PHPUnit\TextUI\XmlConfiguration\Exception
Invalid version comparison operator: "%s"
Error message
Invalid version comparison operator: "%s"
What it means
The phpVersionOperator attribute on <directory> and <file> entries inside <testsuite> (and source restrictions) must be one of PHP's version_compare() operators: !=, <, <=, <>, =, ==, >, >=, eq, ge, gt, le, lt, ne. parseVersionOperator() throws for anything else. This is version_compare syntax, not composer semver syntax, so '^', '~', '=~' and similar are invalid.
Source
Thrown at src/TextUI/Configuration/Xml/Loader.php:976
$value = $element->getAttribute($attribute);
if ($value === '') {
return $default;
}
return $value;
}
/**
* @throws Exception
*
* @return '!='|'<'|'<='|'<>'|'='|'=='|'>'|'>='|'eq'|'ge'|'gt'|'le'|'lt'|'ne'
*/
private function parseVersionOperator(string $operator): string
{
return match ($operator) {
'!=', '<', '<=', '<>', '=', '==', '>', '>=', 'eq', 'ge', 'gt', 'le', 'lt', 'ne' => $operator,
default => throw new Exception(sprintf('Invalid version comparison operator: "%s"', $operator)),
};
}
private function parseInteger(string $value, int $default): int
{
if (is_numeric($value)) {
return (int) $value;
}
return $default;
}
private function php(string $filename, DOMXPath $xpath): Php
{
$includePaths = [];
$includePathNodes = $xpath->query('php/includePath');
View on GitHub (pinned to f123cdb2a2)
Solutions
- Use a version_compare operator: `<`, `<=`, `>`, `>=`, `=`, `==`, `!=`, `<>` or the word forms lt, le, gt, ge, eq, ne
- For 'PHP 8.1 or newer' use phpVersion="8.1.0" phpVersionOperator=">="
- Remember the comparison uses PHP's version_compare() rules, so write full version strings like 8.1.0
Example fix
<!-- before --> <directory phpVersion="8.1" phpVersionOperator="^">tests/Php81</directory> <!-- after --> <directory phpVersion="8.1.0" phpVersionOperator=">=">tests/Php81</directory>
Defensive patterns
Strategy: validation
Validate before calling
const VALID_OPERATORS = ['!=', '<', '<=', '<>', '=', '==', '>', '>=', 'eq', 'ge', 'gt', 'le', 'lt', 'ne'];
function validPhpVersionOperator(string $operator): bool
{
return in_array($operator, VALID_OPERATORS, true);
}
// before writing/generating config:
if (!validPhpVersionOperator($cfg['operator'])) {
throw new InvalidArgumentException('phpVersionOperator must be a version_compare() operator');
} Type guard
/**
* @param string $operator
* @return '!='|'<'|'<='|'<>'|'='|'=='|'>'|'>='|'eq'|'ge'|'gt'|'le'|'lt'|'ne'
*/
function narrowVersionOperator(string $operator): string
{
return in_array($operator, ['!=', '<', '<=', '<>', '=', '==', '>', '>=', 'eq', 'ge', 'gt', 'le', 'lt', 'ne'], true)
? $operator
: throw new InvalidArgumentException("Invalid version comparison operator: {$operator}");
} Try / catch
try {
$configuration = (new \PHPUnit\TextUI\XmlConfiguration\Loader)->loadFile('phpunit.xml');
} catch (\PHPUnit\TextUI\XmlConfiguration\Exception $e) {
if (str_contains($e->getMessage(), 'Invalid version comparison operator')) {
// fix the phpVersionOperator attribute to a version_compare() operator
}
} Prevention
- phpVersionOperator uses version_compare() syntax, not composer semver: no ^, ~, or =~
- When generating phpunit.xml programmatically, whitelist the 14 valid operators
- Prefer the word forms (gte-style: ge, gt, le, lt, eq, ne) if unsure about XML escaping of < and >
When it happens
Trigger: `<directory phpVersion="8.1" phpVersionOperator="^">tests</directory>`; phpVersionOperator="=~"; phpVersionOperator="==="; misspellings like "greate"; copying a composer.json constraint into the attribute.
Common situations: Developers familiar with composer version constraints writing phpunit.xml by hand; copy-pasted snippets from blogs using semver operators; config generators emitting wrong operator strings.
Related errors
- Parameter "%s" does not exist
- Cannot load XML configuration file %s
- The file does not validate against any known schema
- The file does not need to be migrated
- Default test suite is not configured
AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23).
Data as JSON: /api/errors/ef1948d680b523d7.
Report an issue: GitHub.