pestphp/pest · critical · FatalException
The test directory [%s] does not exist.
Error message
The test directory [%s] does not exist.
What it means
Pest computes the test directory as TestSuite rootPath + the value returned by testDirectory() (default 'tests', overridable via the TEST_DIRECTORY env variable or Pest configuration) and verifies it exists during bootstrapping, before any test file loads. When is_dir() fails, BootFiles throws this FatalException and the entire run aborts immediately. It is a configuration/layout error, not a test failure.
Source
Thrown at src/Bootstrappers/BootFiles.php:40
{
/**
* @var array<int, string>
*/
private const array STRUCTURE = [
'Expectations',
'Expectations.php',
'Helpers',
'Helpers.php',
'Pest.php',
];
public function boot(): void
{
$rootPath = TestSuite::getInstance()->rootPath;
$testsPath = $rootPath.DIRECTORY_SEPARATOR.testDirectory();
if (! is_dir($testsPath)) {
throw new FatalException(sprintf('The test directory [%s] does not exist.', $testsPath));
}
foreach (self::STRUCTURE as $filename) {
$filename = sprintf('%s%s%s', $testsPath, DIRECTORY_SEPARATOR, $filename);
if (! file_exists($filename)) {
continue;
}
if (is_dir($filename)) {
$directory = new RecursiveDirectoryIterator($filename);
$iterator = new RecursiveIteratorIterator($directory);
/** @var \DirectoryIterator $file */
foreach ($iterator as $file) {
$this->load($file->__toString());
}
} else {
$this->load($filename);View on GitHub (pinned to 1af74a215c)
Solutions
- Check which directory Pest resolves: the message contains the full path — verify it against where your tests actually live, and fix TEST_DIRECTORY in phpunit.xml/.env if it is wrong.
- Create the missing directory (mkdir -p tests) if the project genuinely should have one and add a bootstrap Pest.php.
- Run vendor/bin/pest from the project root (where composer.json and the tests directory sit) so rootPath is correct.
- On case-sensitive filesystems (Linux CI), confirm the directory casing matches exactly (Tests vs tests).
Example fix
<!-- phpunit.xml --> // before <php><env name="TEST_DIRECTORY" value="specs"/></php> <!-- folder is actually "tests" --> // after <php><env name="TEST_DIRECTORY" value="tests"/></php>
Defensive patterns
Strategy: validation
Validate before calling
// before running pest (CI step or composer script):
$dir = getcwd().'/'.(getenv('TEST_DIRECTORY') ?: 'tests');
if (! is_dir($dir)) {
fwrite(STDERR, "Test directory missing: {$dir}\n");
exit(1);
} Prevention
- Keep the tests directory at the conventional 'tests' path unless a TEST_DIRECTORY override is also configured in phpunit.xml.
- Add a CI sanity step that asserts the test directory exists before invoking vendor/bin/pest.
- Run pest from the project root (composer test script) so rootPath resolution is deterministic.
- After any directory rename, grep phpunit.xml, .env, and CI config for the old path.
When it happens
Trigger: Running vendor/bin/pest when the configured TEST_DIRECTORY points to a folder that does not exist; renaming tests/ to specs/ (or moving it into a subdirectory) without updating phpunit.xml's <env name="TEST_DIRECTORY" .../>; running Pest from the wrong working directory so rootPath resolves to a folder without tests; a case mismatch such as Tests/ vs tests/ on a case-sensitive filesystem.
Common situations: Fresh clones where the repo keeps tests in a non-default location and the env var is not set; CI pipelines that exclude the tests directory from the checkout artifact; monorepos where vendor/bin/pest is executed from the package root instead of the app root; after a directory restructure the .env or phpunit.xml still names the old path.
Related errors
- The fixture file [$file] does not exist.
- Cached failure
- The test expects [%d] argument(s), but the dataset only prov
- Expectation value is not iterable.
- No sequence expectations defined.
AI-assisted analysis of pestphp/pest@1af74a215c (2026-08-21).
Data as JSON: /api/errors/4f70793eeec13d14.
Report an issue: GitHub.