getgrav/grav · error · RuntimeException

json_encode(): failed to encode dependencies

Error message

json_encode(): failed to encode dependencies

What it means

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.

Source

Thrown at system/src/Grav/Framework/Acl/PermissionsReader.php:118

                $current[$defaults['type']] = null;
            }

            $dependencies[$type] = (object)$current;
        }

        // Build dependency tree.
        foreach ($dependencies as $type => $dep) {
            foreach (get_object_vars($dep) as $k => &$val) {
                if (null === $val) {
                    $val = $dependencies[$k] ?? new stdClass();
                }
            }
            unset($val);
        }

        $encoded = json_encode($dependencies);
        if ($encoded === false) {
            throw new RuntimeException('json_encode(): failed to encode dependencies');
        }
        $dependencies = json_decode($encoded, true);

        foreach (static::getDependencies($dependencies) as $type) {
            $defaults = $types[$type] ?? null;
            if ($defaults) {
                static::$types[$type] = static::addDefaults($defaults);
            }
        }
    }

    /**
     * @param array $dependencies
     * @return array
     */
    protected static function getDependencies(array $dependencies): array
    {
        $list = [[]];

View on GitHub (pinned to 6040efed04)

Solutions

  1. Identify the offending plugin: disable recently added plugins one by one (or bisect) and re-trigger permission compilation to isolate which YAML is unserializable.
  2. Re-save the plugin's permissions.yaml explicitly as UTF-8 without BOM; replace smart quotes/dashes with plain ASCII or proper UTF-8.
  3. If you build permission data in code, ensure only scalars/arrays (no closures, resources, objects with circular refs) enter labels, descriptions, and dependencies.
  4. Run json_last_error() diagnostics on a minimal reproduction of the YAML payload to confirm the exact cause (malformed UTF-8 vs recursion).

Example fix

# user/plugins/myplugin/permissions.yaml  (before: saved as Windows-1252)
# access:
#   admin.myplugin:
#     label: "It’s broken…"      # non-UTF-8 bytes -> json_encode fails

# after: re-encode file to UTF-8
#   admin.myplugin:
#     label: "It's fixed..."       # plain UTF-8/ASCII
Defensive patterns

Strategy: validation

Validate before calling

// validate plugin permission strings are UTF-8-clean before install
$yaml = file_get_contents('user/plugins/myplugin/permissions.yaml');
if (!mb_check_encoding($yaml, 'UTF-8')) {
    exit('permissions.yaml is not valid UTF-8; re-save the file as UTF-8' . PHP_EOL);
}
if (json_encode(json_decode(json_encode(yaml_parse($yaml) ?? []))) === false) {
    exit('Permission data not JSON-serializable: ' . json_last_error_msg() . PHP_EOL);
}

Try / catch

try {
    PermissionsReader::read(...);
} catch (\RuntimeException $e) {
    if (str_contains($e->getMessage(), 'json_encode')) {
        // bisect: disable newest plugins until compilation succeeds
        error_log('Unserializable permission metadata; check plugin YAML encoding');
    }
    throw;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of getgrav/grav@6040efed04 (2026-08-17). Data as JSON: /api/errors/0d300d4c009659c1. Report an issue: GitHub.