sebastianbergmann/phpunit · error · InvalidDataProviderException
The key must be an integer or a string, %s given
Error message
The key must be an integer or a string, %s given
What it means
Thrown while iterating a provider's returned data when a key is neither an integer nor a string (get_debug_type() names the actual type in the message). PHPUnit uses each key as the dataset name in test IDs and output, so arrays keyed by, e.g., floats or objects are rejected.
Source
Thrown at src/Metadata/Api/DataProvider.php:182
'Data Provider method %s::%s() does not return an iterable',
$className,
$methodName,
),
);
}
} catch (Throwable $e) {
Event\Facade::emitter()->dataProviderMethodFinished(
$testMethodValueObject,
...$methodsCalled,
);
throw InvalidDataProviderException::forException($e, $providerLabel);
}
try {
foreach ($data as $key => $value) {
if (!is_int($key) && !is_string($key)) {
throw new InvalidDataProviderException(
sprintf(
'The key must be an integer or a string, %s given',
get_debug_type($key),
),
);
}
if ($key === '') {
throw new InvalidDataProviderException(
'The key must not be an empty string',
);
}
if (!is_array($value)) {
throw new InvalidDataProviderException(
sprintf(
'Data set %s provided by %s is invalid, expected array but got %s',
$this->formatKey($key),View on GitHub (pinned to f123cdb2a2)
Solutions
- Ensure every dataset key is an int or a non-empty string; cast keys: [(string) $id => $row]
- Rebuild the provider with array_values() or a foreach that assigns sequential integer keys
- Inspect the provider output (var_export) to find the offending key of the reported type
Example fix
// before
public static function provideCases(): array
{
$rows = $repository->all(); // keys are float ids
return $rows;
}
// after
public static function provideCases(): array
{
$cases = [];
foreach ($repository->all() as $id => $row) {
$cases['row ' . $id] = $row;
}
return $cases;
} Defensive patterns
Strategy: validation
Validate before calling
// Normalize keys before returning from a provider
$cases = [];
foreach ($raw as $key => $value) {
if (!is_int($key) && !is_string($key)) {
$key = 'case ' . count($cases);
}
$cases[$key] = $value;
}
return $cases; Prevention
- Cast dynamic keys to string when building providers: [(string) $id => $row]
- Use array_values($data) when keys carry no meaning
- Inspect provider output with var_export() when adding non-standard key sources
When it happens
Trigger: A provider returning [0.5 => [...]] or [$objectKey => [...]] (object/array keys from array_fill_keys or dynamic maps); generators yielding non-scalar keys.
Common situations: Providers built from array_combine with float/string-cast values; spreads of enums-as-keys; data derived from JSON with unexpected key types.
Related errors
- The key must not be an empty string
- Data Provider method %s::%s() is not public
- Data Provider method %s::%s() is not static
- Data Provider method %s::%s() expects an argument
- Data Provider method %s::%s() does not return an iterable
AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23).
Data as JSON: /api/errors/4de32779a6a3310c.
Report an issue: GitHub.