{"record":{"id":"373c6656e8e986ff","repo":"symfony/process","slug":"s-yielded-a-value-of-type-s-but-only-scalars-and-stream","errorCode":null,"errorMessage":"\"%s\" yielded a value of type \"%s\", but only scalars and stream resources are supported.","messagePattern":"\"(.+?)\" yielded a value of type \"(.+?)\", but only scalars and stream resources are supported\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"Pipes/AbstractPipes.php","lineNumber":116,"sourceCode":"     *\n     * @throws InvalidArgumentException When an input iterator yields a non supported value\n     */\n    protected function write(): ?array\n    {\n        if (!isset($this->pipes[0])) {\n            return null;\n        }\n        $input = $this->input;\n\n        if ($input instanceof \\Iterator) {\n            if (!$input->valid()) {\n                $input = null;\n            } elseif (\\is_resource($input = $input->current())) {\n                stream_set_blocking($input, false);\n            } elseif (!isset($this->inputBuffer[0])) {\n                if (!\\is_string($input)) {\n                    if (!\\is_scalar($input)) {\n                        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)));\n                    }\n                    $input = (string) $input;\n                }\n                $this->inputBuffer = $input;\n                $this->input->next();\n                $input = null;\n            } else {\n                $input = null;\n            }\n        }\n\n        $r = $e = [];\n        $w = [$this->pipes[0]];\n\n        // let's have a look if something changed in streams\n        if (false === @stream_select($r, $w, $e, 0, 0)) {\n            return null;\n        }","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/symfony/process/blob/99b85026db14a68f02c6f3eeb01a1170ca25c491/Pipes/AbstractPipes.php#L98-L134","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nfunction rows(): Generator { foreach ($data as $row) yield $row; } // yields arrays\n$process = new Process($cmd, null, null, rows());\n\n// after\nfunction rows(): Generator { foreach ($data as $row) yield json_encode($row); }\n$process = new Process($cmd, null, null, rows());","handlingStrategy":"type-guard","validationCode":"$values = is_iterable($input) ? iterator_to_array((function () use ($input) { yield from $input; })()) : [$input];\nforeach ($values as $v) {\n    if (!is_scalar($v) && !is_resource($v) && null !== $v) {\n        throw new \\InvalidArgumentException('Input iterable must yield scalars or stream resources, got: '.get_debug_type($v));\n    }\n}","typeGuard":"function isValidProcessInput(mixed $v): bool {\n    return is_string($v) || is_scalar($v) || is_resource($v);\n}","tryCatchPattern":"try {\n    $process->run();\n} catch (\\InvalidArgumentException $e) {\n    if (str_contains($e->getMessage(), 'only scalars and stream resources are supported')) {\n        // inspect the input generator: something yielded a non-scalar\n    }\n    throw $e;\n}","preventionTips":["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."],"tags":["php","symfony-process","input","type-error"],"backgroundTag":"invalid-argument-value","analyzedSha":"99b85026db14a68f02c6f3eeb01a1170ca25c491","analyzedAt":"2026-09-14T11:23:33.683Z","contentChangedAt":"2026-09-14T11:23:33.683Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}