{"record":{"id":"0d300d4c009659c1","repo":"getgrav/grav","slug":"json-encode-failed-to-encode-dependencies","errorCode":null,"errorMessage":"json_encode(): failed to encode dependencies","messagePattern":"json_encode\\(\\): failed to encode dependencies","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"system/src/Grav/Framework/Acl/PermissionsReader.php","lineNumber":118,"sourceCode":"                $current[$defaults['type']] = null;\n            }\n\n            $dependencies[$type] = (object)$current;\n        }\n\n        // Build dependency tree.\n        foreach ($dependencies as $type => $dep) {\n            foreach (get_object_vars($dep) as $k => &$val) {\n                if (null === $val) {\n                    $val = $dependencies[$k] ?? new stdClass();\n                }\n            }\n            unset($val);\n        }\n\n        $encoded = json_encode($dependencies);\n        if ($encoded === false) {\n            throw new RuntimeException('json_encode(): failed to encode dependencies');\n        }\n        $dependencies = json_decode($encoded, true);\n\n        foreach (static::getDependencies($dependencies) as $type) {\n            $defaults = $types[$type] ?? null;\n            if ($defaults) {\n                static::$types[$type] = static::addDefaults($defaults);\n            }\n        }\n    }\n\n    /**\n     * @param array $dependencies\n     * @return array\n     */\n    protected static function getDependencies(array $dependencies): array\n    {\n        $list = [[]];","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/getgrav/grav/blob/6040efed04efa69b8209448ed81308e7c24147c2/system/src/Grav/Framework/Acl/PermissionsReader.php#L100-L136","documentation":"While compiling permission definitions, PermissionsReader normalizes its dependency tree by round-tripping it through json_encode/json_decode. json_encode() returns false when the payload contains data PHP cannot serialize — invalid UTF-8 sequences, resources, INF/NAN, or circular references — and that failure is rethrown as this RuntimeException. The bad data ultimately comes from permission metadata (labels, descriptions, dependency maps) contributed by plugins.","triggerScenarios":"A plugin's permissions.yaml (or plugin-defined permission arrays) containing non-UTF-8 bytes (Windows-1252 curly quotes, BOM-pasted text) that end up in dependency values; a plugin programmatically attaching a closure/resource into permission dependency data; YAML aliases creating circular structures in dependency objects.","commonSituations":"Plugin YAML edited in a non-UTF-8 editor on Windows; copy-pasting marketing text with smart quotes into permission descriptions; permissions cache warm-up failing during `bin/grav clearcache` or first admin request after installing a plugin; PHP version change surfacing previously-tolerated malformed strings.","solutions":["Identify the offending plugin: disable recently added plugins one by one (or bisect) and re-trigger permission compilation to isolate which YAML is unserializable.","Re-save the plugin's permissions.yaml explicitly as UTF-8 without BOM; replace smart quotes/dashes with plain ASCII or proper UTF-8.","If you build permission data in code, ensure only scalars/arrays (no closures, resources, objects with circular refs) enter labels, descriptions, and dependencies.","Run json_last_error() diagnostics on a minimal reproduction of the YAML payload to confirm the exact cause (malformed UTF-8 vs recursion)."],"exampleFix":"# user/plugins/myplugin/permissions.yaml  (before: saved as Windows-1252)\n# access:\n#   admin.myplugin:\n#     label: \"It’s broken…\"      # non-UTF-8 bytes -> json_encode fails\n\n# after: re-encode file to UTF-8\n#   admin.myplugin:\n#     label: \"It's fixed...\"       # plain UTF-8/ASCII","handlingStrategy":"validation","validationCode":"// validate plugin permission strings are UTF-8-clean before install\n$yaml = file_get_contents('user/plugins/myplugin/permissions.yaml');\nif (!mb_check_encoding($yaml, 'UTF-8')) {\n    exit('permissions.yaml is not valid UTF-8; re-save the file as UTF-8' . PHP_EOL);\n}\nif (json_encode(json_decode(json_encode(yaml_parse($yaml) ?? []))) === false) {\n    exit('Permission data not JSON-serializable: ' . json_last_error_msg() . PHP_EOL);\n}","typeGuard":null,"tryCatchPattern":"try {\n    PermissionsReader::read(...);\n} catch (\\RuntimeException $e) {\n    if (str_contains($e->getMessage(), 'json_encode')) {\n        // bisect: disable newest plugins until compilation succeeds\n        error_log('Unserializable permission metadata; check plugin YAML encoding');\n    }\n    throw;\n}","preventionTips":["Save all plugin YAML as UTF-8 without BOM; avoid smart quotes in labels/descriptions.","Run mb_check_encoding() on imported permission files during CI.","Keep only scalars and arrays in permission metadata — no closures, resources, or circular references."],"tags":["grav","acl","permissions","json-encode","utf-8","yaml"],"backgroundTag":"json-encode-failed","analyzedSha":"6040efed04efa69b8209448ed81308e7c24147c2","analyzedAt":"2026-08-17T05:07:31.593Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}