symfony/process · error · InvalidArgumentException
" " yielded a value of type " ", but only scalars and…
Error message
"%s" yielded a value of type "%s", but only scalars and stream resources are supported.
What it means
When a Process is given an iterable input (e.g. a generator), each yielded value must be a string, a scalar castable to string, or a stream resource. If the iterator yields an object, array, null, or other non-scalar non-resource value, AbstractPipes::write throws InvalidArgumentException because such a value cannot be written to the process's stdin pipe.
Solutions
- Cast or serialize values before yielding: yield json_encode($row) instead of yield $row.
- Ensure yielded values are string, int, float, bool, or a stream resource.
- Map the iterable before passing it: new Process($cmd, null, null, (function () { foreach ($rows as $r) yield (string) $r; })()).
- If yielding null to signal end-of-input, stop iterating instead — the pipes layer handles iterator exhaustion itself.
Example fix
// before
function rows(): Generator { foreach ($data as $row) yield $row; } // yields arrays
$process = new Process($cmd, null, null, rows());
// after
function rows(): Generator { foreach ($data as $row) yield json_encode($row); }
$process = new Process($cmd, null, null, rows()); Defensive patterns
Strategy: type-guard
Validate before calling
$values = is_iterable($input) ? iterator_to_array((function () use ($input) { yield from $input; })()) : [$input];
foreach ($values as $v) {
if (!is_scalar($v) && !is_resource($v) && null !== $v) {
throw new \InvalidArgumentException('Input iterable must yield scalars or stream resources, got: '.get_debug_type($v));
}
} Type guard
function isValidProcessInput(mixed $v): bool {
return is_string($v) || is_scalar($v) || is_resource($v);
} Try / catch
try {
$process->run();
} catch (\InvalidArgumentException $e) {
if (str_contains($e->getMessage(), 'only scalars and stream resources are supported')) {
// inspect the input generator: something yielded a non-scalar
}
throw $e;
} Prevention
- Always yield strings from input generators (json_encode/serialize explicitly).
- Add a unit test asserting every yielded input value passes is_scalar||is_resource.
- Avoid yielding objects/arrays/DTOs directly; cast at the generator boundary.
- Remember null ends input handling only via iterator exhaustion — don't rely on yielding null.
When it happens
Trigger: Passing a Traversable/generator to Process::setInput or the $input constructor argument where a yielded value is not scalar and not a resource, e.g. yielding arrays or objects; the exception fires during readAndWrite while pumping input to a running process.
Common situations: Feeding a generator of decoded JSON entries (arrays) instead of encoded strings; yielding ORM entities or DTO objects; forgetting to json_encode/serialize before yielding.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- A temporary file could not be opened to write the process…
- Process is already running.
- The provided cwd " " does not exist.
- Pass the callback to the "Process::start" method or call…
- Pass the callback to the "Process::start" method or call…
AI-assisted analysis of symfony/process@99b85026db (2026-09-14).
Data as JSON: /api/errors/373c6656e8e986ff.
Report an issue: GitHub.
Appendix: source
Thrown at Pipes/AbstractPipes.php:116
*
* @throws InvalidArgumentException When an input iterator yields a non supported value
*/
protected function write(): ?array
{
if (!isset($this->pipes[0])) {
return null;
}
$input = $this->input;
if ($input instanceof \Iterator) {
if (!$input->valid()) {
$input = null;
} elseif (\is_resource($input = $input->current())) {
stream_set_blocking($input, false);
} elseif (!isset($this->inputBuffer[0])) {
if (!\is_string($input)) {
if (!\is_scalar($input)) {
throw new InvalidArgumentException(\sprintf('"%s" yielded a value of type "%s", but only scalars and stream resources are supported.', get_debug_type($this->input), get_debug_type($input)));
}
$input = (string) $input;
}
$this->inputBuffer = $input;
$this->input->next();
$input = null;
} else {
$input = null;
}
}
$r = $e = [];
$w = [$this->pipes[0]];
// let's have a look if something changed in streams
if (false === @stream_select($r, $w, $e, 0, 0)) {
return null;
}View on GitHub (pinned to 99b85026db)