pestphp/pest · error · AfterAllWithinDescribe
The [afterAll] hook may not be used inside a [describe] bloc
Error message
The [afterAll] hook may not be used inside a [describe] block. Please move it to the top level of [%s].
What it means
Symmetric to beforeAll: afterAll() registers a once-per-file teardown hook on the TestSuite, and calling it inside a describe() block throws AfterAllWithinDescribe with the file name. Suite-level All-hooks must live at the top level of the test file; each-variants are unrestricted.
Source
Thrown at src/Functions.php:161
if (! function_exists('afterEach')) {
/**
* @param-closure-this TestCall $closure
*/
function afterEach(?Closure $closure = null): AfterEachCall
{
$filename = Backtrace::testFile();
return new AfterEachCall(TestSuite::getInstance(), $filename, $closure);
}
}
if (! function_exists('afterAll')) {
function afterAll(Closure $closure): void
{
if (DescribeCall::describing() !== []) {
$filename = Backtrace::testFile();
throw new AfterAllWithinDescribe($filename);
}
TestSuite::getInstance()->afterAll->set($closure);
}
}
if (! function_exists('covers')) {
/**
* @param array<int, string>|string $classesOrFunctions
*/
function covers(array|string ...$classesOrFunctions): void
{
$filename = Backtrace::testFile();
$beforeEachCall = (new BeforeEachCall(TestSuite::getInstance(), $filename));
$beforeEachCall->covers(...$classesOrFunctions);
$beforeEachCall->group('__pest_mutate_only');View on GitHub (pinned to 1af74a215c)
Solutions
- Move the afterAll() call to the top level of the test file.
- Use afterEach() inside the describe for group-scoped teardown.
- Split the describe into its own file if it truly needs file-scoped teardown independent of other groups.
Example fix
// before
describe('imports', function () {
afterAll(fn () => cleanupStorage()); // throws
it('imports csv', fn () => ...);
});
// after
afterAll(fn () => cleanupStorage());
describe('imports', function () {
it('imports csv', fn () => ...);
}); Defensive patterns
Strategy: validation
Prevention
- Keep afterAll at the file's top level, grouped with beforeAll for readability.
- Use afterEach() inside describe blocks for scoped teardown.
- When porting Jest/Jasmine suites, remember only Pest's each-hooks may nest inside describe.
When it happens
Trigger: Calling afterAll(function () { ... }) inside describe('...', function () { ... }); refactoring teardown into groups; copy-pasting a describe body that contained hooks from a Jest-style project.
Common situations: Grouping tests late in a file's life and moving hooks with them; migrating from Jest/Jasmine where afterAll inside describe is standard; attempting teardown scoped to one feature group.
Related errors
- The [beforeAll] hook may not be used inside a [describe] blo
- The test directory [%s] does not exist.
- Cached failure
- The test expects [%d] argument(s), but the dataset only prov
- Expectation value is not iterable.
AI-assisted analysis of pestphp/pest@1af74a215c (2026-08-21).
Data as JSON: /api/errors/311efec487881850.
Report an issue: GitHub.