sebastianbergmann/phpunit · error · InvalidDataProviderException
Data Provider callable does not return an iterable
Error message
Data Provider callable does not return an iterable
What it means
The test method uses a #[DataProviderClosure(fn () => ...)] attribute (a Closure as data provider). PHPUnit invoked the closure and requires its return value to be iterable (array or Traversable), because each entry becomes one data set. The closure returned something else, so the test errors out before any data set runs.
Source
Thrown at src/Metadata/Api/DataProvider.php:260
$e->getMessage(),
$e->getCode(),
$e,
);
}
}
foreach ($dataProviderClosure as $_dataProvider) {
assert($_dataProvider instanceof DataProviderClosureMetadata);
$providerLabel = sprintf('callable provided to %s::%s()', $testClassName, $testMethod->getName());
$validateArgumentCount = $testMethodIsNonVariadic && $_dataProvider->validateArgumentCount();
try {
$callable = $_dataProvider->closure();
$data = $callable();
if (!is_iterable($data)) {
throw new InvalidDataProviderException(
'Data Provider callable does not return an iterable',
);
}
} catch (Throwable $e) {
Event\Facade::emitter()->dataProviderMethodFinished(
$testMethodValueObject,
...$methodsCalled,
);
throw InvalidDataProviderException::forException($e, $providerLabel);
}
foreach ($data as $key => $value) {
if (!is_int($key) && !is_string($key)) {
Event\Facade::emitter()->dataProviderMethodFinished(
$testMethodValueObject,
...$methodsCalled,
);View on GitHub (pinned to f123cdb2a2)
Solutions
- Make the closure return an iterable of argument arrays: #[DataProviderClosure(fn () => [[1, 2], [3, 4]])].
- If the closure delegates to another function, verify that function's return value is iterable.
- Check for early exits that implicitly return null.
Example fix
// before #[DataProviderClosure(fn () => null)] // after #[DataProviderClosure(fn () => [[1, 2], [3, 4]])]
Defensive patterns
Strategy: type-guard
Validate before calling
// Meta-test: the closure must return an iterable before wiring it into #[DataProviderClosure] $closure = fn (): array => [[1, 2]]; self::assertIsIterable($closure());
Type guard
function returnsIterableDataProvider(Closure $provider): bool
{
return is_iterable($provider());
} Prevention
- Declare the closure's return type so PHP itself rejects bad returns: fn (): array => ....
- Smoke-test the closure in a unit test before attaching it via #[DataProviderClosure].
- Watch for early returns that implicitly return null.
When it happens
Trigger: #[DataProviderClosure(fn () => null)] (implicit or explicit null return), fn () => 'rows' (string), or any closure returning a scalar or a non-Traversable object. Arrays and Generators are fine.
Common situations: Closures with an early return that implicitly returns null; refactoring a method provider into a closure and dropping the return statement; closures returning a single value instead of a list of argument arrays.
Related errors
- Data set %s provided by %s is invalid, expected array but go
- The key "%s" has already been defined by provider %s
- Empty data set provided by data provider
- Subscriber "%s" does not implement any known interface - did
- Unknown event type "%s"
AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23).
Data as JSON: /api/errors/82bbea2097a6b96c.
Report an issue: GitHub.