laravel/framework · error · UnexpectedValueException
::reduceSpread expects reducer to return an array, but got…
Error message
%s::reduceSpread expects reducer to return an array, but got a '%s' instead.
What it means
Thrown by reduceSpread(callable $callback, ...$initial) when the reducer callable returns a non-array value on any iteration. reduceSpread expects each step to return an array so it can spread the result as arguments into the next call (list-destructuring pattern); a non-array return breaks that contract and throws UnexpectedValueException with the class and actual type.
Solutions
- Ensure the reducer always returns an array on every code path (including the final iteration).
- Use plain reduce() if you only need a single accumulated value.
- Add a return-type check / unit test asserting array output for each branch.
Example fix
// before
$result = $collection->reduceSpread(function ($carry, $item) {
if ($item === null) return null;
return [$carry[0] + $item];
}, 0);
// after
$result = $collection->reduceSpread(function ($carry, $item) {
if ($item === null) return $carry;
return [$carry[0] + $item];
}, 0); Defensive patterns
Strategy: validation
Validate before calling
// Verify the reducer returns array on a sample before relying on it
$test = $callback(...array_merge($initial, [$collection->first(), $collection->keys()->first()]));
if (! is_array($test)) {
throw new \UnexpectedValueException('reducer must return array');
} Type guard
// Ensure every branch returns an array
$callback = function (array $carry, $item): array {
// ...all paths return array
return $carry;
}; Try / catch
try {
$result = $collection->reduceSpread($callback, ...$initial);
} catch (\UnexpectedValueException $e) {
// fall back to plain reduce
$result = $collection->reduce($callback, $initial);
} Prevention
- Always type the reducer return as array in its signature.
- Use reduce() instead of reduceSpread() if a single scalar suffices.
- Unit-test each branch of the callback for array output.
When it happens
Trigger: Passing a reducer that returns a scalar/object/null on some iteration; forgetting to return the accumulator array; early-return inside the callback that yields null.
Common situations: Refactoring a reduce into reduceSpread for the spread-arg ergonomics; callback that conditionally returns and misses a branch; third-party reducer reused without adapting its return shape.
Related errors
- Array value for key [ ] must be a boolean, found.
- Array value for key [ ] must be a float, found.
- Array value for key [ ] must be a string, found.
- Array value for key [ ] must be an array, found.
- Array value for key [ ] must be an integer, found.
AI-assisted analysis of laravel/framework@e0f6eb3518 (2026-08-11).
Data as JSON: /api/errors/4bfdd2a046c2ea37.
Report an issue: GitHub.
Appendix: source
Thrown at src/Illuminate/Collections/Traits/EnumeratesValues.php:889
/**
* Reduce the collection to multiple aggregate values.
*
* @param callable $callback
* @param mixed ...$initial
* @return array
*
* @throws \UnexpectedValueException
*/
public function reduceSpread(callable $callback, ...$initial)
{
$result = $initial;
foreach ($this as $key => $value) {
$result = call_user_func_array($callback, array_merge($result, [$value, $key]));
if (! is_array($result)) {
throw new UnexpectedValueException(sprintf(
"%s::reduceSpread expects reducer to return an array, but got a '%s' instead.",
class_basename(static::class), gettype($result)
));
}
}
return $result;
}
/**
* Reduce an associative collection to a single value.
*
* @template TReduceWithKeysInitial
* @template TReduceWithKeysReturnType
*
* @param callable(TReduceWithKeysInitial|TReduceWithKeysReturnType, TValue, TKey): TReduceWithKeysReturnType $callback
* @param TReduceWithKeysInitial $initial
* @return TReduceWithKeysInitial|TReduceWithKeysReturnTypeView on GitHub (pinned to e0f6eb3518)