{"record":{"id":"3607e05e5909d581","repo":"getgrav/grav","slug":"cache-values-must-be-array-or-traversable-s-gi","errorCode":null,"errorMessage":"Cache values must be array or Traversable, \"%s\" given","messagePattern":"Cache values must be array or Traversable, \"(.+?)\" given","errorType":"validation","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"system/src/Grav/Framework/Cache/CacheTrait.php","lineNumber":187,"sourceCode":"            }\n        }\n\n        return $values;\n    }\n\n    /**\n     * @param iterable $values\n     * @param null|int|DateInterval $ttl\n     * @return bool\n     * @throws InvalidArgumentException\n     */\n    public function setMultiple(iterable $values, DateInterval|int|null $ttl = null): bool\n    {\n        if ($values instanceof Traversable) {\n            $values = iterator_to_array($values, true);\n        } elseif (!is_array($values)) {\n            $isObject = is_object($values);\n            throw new InvalidArgumentException(\n                sprintf(\n                    'Cache values must be array or Traversable, \"%s\" given',\n                    $isObject ? $values::class : gettype($values)\n                )\n            );\n        }\n\n        $keys = array_keys($values);\n\n        if (empty($keys)) {\n            return true;\n        }\n\n        $this->validateKeys($keys);\n\n        $ttl = $this->convertTtl($ttl);\n\n        // If a negative or zero TTL is provided, the item MUST be deleted from the cache.","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/getgrav/grav/blob/6040efed04efa69b8209448ed81308e7c24147c2/system/src/Grav/Framework/Cache/CacheTrait.php#L169-L205","documentation":"CacheTrait::setMultiple() (PSR-16 'set multiple') requires its values argument to be an array or Traversable; anything else triggers InvalidArgumentException('Cache values must be array or Traversable, ...'). As with the other multi-ops the parameter is natively typed iterable, so the exception guards internal/legacy call paths while typical userland misuse surfaces as TypeError first.","triggerScenarios":"Calling $cache->setMultiple('serialized-string-of-values'); passing a generator-returning false/early-return value (null) straight into setMultiple(); passing an ArrayAccess object that is not Traversable; forwarding a decoded JSON scalar (string/number) instead of the expected object-as-array.","commonSituations":"json_decode($json) without the second argument returning an object (stdClass is Traversable? no — stdClass is NOT Traversable, so decoding a JSON object without `true` and passing it raises this); caching a single value and forgetting key=>value pairing; API responses that are scalars rather than maps.","solutions":["Always pass a key=>value map: $cache->setMultiple(['menu' => $menu, 'pages' => $pages], $ttl).","Use json_decode($json, true) so decoded objects become arrays, which pass the check.","For single values, use set($key, $value) instead of setMultiple()."],"exampleFix":"// before\n$cache->setMultiple(json_decode($payload)); // stdClass -> InvalidArgumentException\n\n// after\n$cache->setMultiple((array)json_decode($payload, true));","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function normalizeValues(mixed $values): array\n{\n    if ($values instanceof \\Traversable) {\n        return iterator_to_array($values, true);\n    }\n    if ($values instanceof \\stdClass) {\n        return (array) $values; // json_decode without assoc=true\n    }\n    return is_array($values) ? $values : throw new \\InvalidArgumentException('values must be iterable');\n}\n\n$cache->setMultiple(normalizeValues($values), $ttl);","tryCatchPattern":null,"preventionTips":["Use json_decode($json, true) when decoded data feeds setMultiple().","Keep values in key=>value map form; use set() for single items.","Guard generator-returning helpers: a null/false early return must not reach setMultiple()."],"tags":["grav","cache","psr-16","invalid-argument","iterable"],"backgroundTag":"psr16-invalid-argument","analyzedSha":"6040efed04efa69b8209448ed81308e7c24147c2","analyzedAt":"2026-08-17T05:07:31.593Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}