sebastianbergmann/phpunit · error · Exception
The tests aggregated by this TestSuite were already run
Error message
The tests aggregated by this TestSuite were already run
What it means
Thrown by TestSuite::run() when the same TestSuite instance is run a second time; the wasRun flag is set on the first run and never reset. The guard exists because TestSuite mutates state while running (counts, iterators, attached listeners), so reusing an instance would corrupt results.
Source
Thrown at src/Framework/TestSuite.php:398
$tests[] = $test;
}
return $tests;
}
/**
* @throws Event\RuntimeException
* @throws Exception
* @throws InvalidArgumentException
* @throws NoPreviousThrowableException
* @throws UnintentionallyCoveredCodeException
*/
public function run(): void
{
if ($this->wasRun) {
// @codeCoverageIgnoreStart
throw new Exception('The tests aggregated by this TestSuite were already run');
// @codeCoverageIgnoreEnd
}
$this->wasRun = true;
if ($this->isEmpty()) {
return;
}
$emitter = Event\Facade::emitter();
$testSuiteValueObjectForEvents = Event\TestSuite\TestSuiteBuilder::from($this);
$emitter->testSuiteStarted($testSuiteValueObjectForEvents);
if (!$this->invokeMethodsBeforeFirstTest($emitter, $testSuiteValueObjectForEvents)) {
return;
}
View on GitHub (pinned to f123cdb2a2)
Solutions
- Build a fresh TestSuite (re-run the suite builder/loader) for every run instead of reusing the instance
- Remove the manual $suite->run() call if a TestRunner already executes the suite
- Restructure retry logic to rebuild the suite between attempts
Example fix
// before
$suite = $loader->load('tests');
$suite->run();
$suite->run(); // Exception: already run
// after
foreach (range(1, 2) as $i) {
$loader->load('tests')->run(); // fresh suite each time
} Defensive patterns
Strategy: validation
Prevention
- Treat TestSuite objects as single-use: rebuild via the loader for every run
- Never cache suites across retry attempts or runner phases
- Let a single TestRunner own the run() call; remove manual invocations
When it happens
Trigger: Calling $suite->run() twice on the same object, e.g. running a cached/shared TestSuite once manually and again through a TestRunner, or re-running inside a custom orchestrator loop without rebuilding the suite.
Common situations: Custom test runners or retry logic that reuses a suite built once; embedding PHPUnit in another tool that runs suites on multiple phases; caching suites in long-running worker processes.
Related errors
- Class %s is abstract
- Class %s is not a subclass of %s
- The current item is not a TestSuite instance and therefore d
- Default test suite is not configured
- Test directory "%s" not found
AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23).
Data as JSON: /api/errors/83f97574234ebd43.
Report an issue: GitHub.