getgrav/grav · error · InvalidArgumentException

Cache key length must be greater than zero

Error message

Cache key length must be greater than zero

What it means

CacheTrait::validateKey() rejects empty strings: an empty key is ambiguous (often a symptom of a failed lookup upstream) and PSR-16 reserves it as invalid. The check uses isset($key[0]) so any zero-length string triggers InvalidArgumentException('Cache key length must be greater than zero').

Source

Thrown at system/src/Grav/Framework/Cache/CacheTrait.php:314

    }

    /**
     * @param string|mixed $key
     * @return void
     * @throws InvalidArgumentException
     */
    protected function validateKey(mixed $key): void
    {
        if (!is_string($key)) {
            throw new InvalidArgumentException(
                sprintf(
                    'Cache key must be string, "%s" given',
                    get_debug_type($key)
                )
            );
        }
        if (!isset($key[0])) {
            throw new InvalidArgumentException('Cache key length must be greater than zero');
        }
        if (strlen($key) > 64) {
            throw new InvalidArgumentException(
                sprintf('Cache key length must be less than 65 characters, key had %d characters', strlen($key))
            );
        }
        if (strpbrk($key, '{}()/\@:') !== false) {
            throw new InvalidArgumentException(
                sprintf('Cache key "%s" contains reserved characters {}()/\@:', $key)
            );
        }
    }

    /**
     * @param array $keys
     * @return void
     * @throws InvalidArgumentException
     */

View on GitHub (pinned to 6040efed04)

Solutions

  1. Guard the variable: if ($key === '') { fall back to a computed key or skip caching }.
  2. Prefix keys so they can never be empty: $key = 'page-' . $slug; even a missing slug yields a non-empty string.
  3. Validate multi-op inputs: array_filter($keys, 'strlen') before getMultiple/deleteMultiple.

Example fix

// before
$cache->get($this->route()); // returns '' for home -> throws

// after
$route = $this->route() ?: '/';
$cache->get('page-' . md5($route));
Defensive patterns

Strategy: validation

Validate before calling

if (!is_string($key) || $key === '') {
    $key = 'fallback-' . md5(json_encode($context) ?: 'default');
}
$cache->get($key);

Prevention

When it happens

Trigger: Calling $cache->get('') or $cache->get($name) where $name is '' because a variable defaulted to empty (failed ->value() call, missing config key, optional route parameter absent); multi-ops where an array contains '' among the keys.

Common situations: Caching keyed by an optional URL segment or field that is absent on some records; null coalescing that produces '' instead of a fallback; trimming user input to nothing and using it as a key; empty defaults from configuration (system.yaml -> custom cache key prefix missing).

Related errors


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