symfony/symfony · error · Symfony\Component\Cache\Exception\InvalidArgumentException

Namespace contains "%s" but only characters in [-+_.A-Za-z0-

Error message

Namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.

What it means

FilesystemCommonTrait::init() builds the cache directory by appending the namespace to the base directory, so the namespace becomes a literal path segment. Characters outside [-+_.A-Za-z0-9] (notably /, \, :, NUL) could cause path traversal or invalid paths, so they are rejected up front.

Source

Thrown at src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php:35

 * @author Nicolas Grekas <p@tchwork.com>
 *
 * @internal
 */
trait FilesystemCommonTrait
{
    private string $directory;
    private string $tmpSuffix;

    private function init(string $namespace, ?string $directory): void
    {
        if (!isset($directory[0])) {
            $directory = sys_get_temp_dir().\DIRECTORY_SEPARATOR.'symfony-cache';
        } else {
            $directory = realpath($directory) ?: $directory;
        }
        if (isset($namespace[0])) {
            if (preg_match('#[^-+_.A-Za-z0-9]#', $namespace, $match)) {
                throw new InvalidArgumentException(\sprintf('Namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0]));
            }
            $directory .= \DIRECTORY_SEPARATOR.$namespace;
        } else {
            $directory .= \DIRECTORY_SEPARATOR.'@';
        }
        if (!is_dir($directory)) {
            @mkdir($directory, 0o777, true);
        }
        $directory .= \DIRECTORY_SEPARATOR;
        // On Windows the whole path is limited to 258 chars
        if ('\\' === \DIRECTORY_SEPARATOR && \strlen($directory) > 234) {
            throw new InvalidArgumentException(\sprintf('Cache directory too long (%s).', $directory));
        }

        $this->directory = $directory;
    }

    protected function doClear(string $namespace): bool

View on GitHub (pinned to 698e28026c)

Solutions

  1. Restrict the namespace to [-+_.A-Za-z0-9] (use - or _ as separators).
  2. Hash or slugify arbitrary input: preg_replace('#[^-+_.A-Za-z0-9]#', '_', $input).
  3. For per-tenant separation that needs '/', rely on the adapter's own hashed sharding instead of the namespace.

Example fix

// before
new FilesystemAdapter('tenant:42', 0, $dir);

// after
new FilesystemAdapter('tenant_42', 0, $dir);
Defensive patterns

Strategy: validation

Validate before calling

$ns = preg_replace('#[^-+_.A-Za-z0-9]#', '_', $rawNamespace);
new FilesystemAdapter($ns, 0, $dir);

Type guard

function isValidNamespace(string $ns): bool {
    return preg_match('#^[^-+_.A-Za-z0-9]*$#', $ns) || !preg_match('#[^-+_.A-Za-z0-9]#', $ns);
}

Prevention

When it happens

Trigger: new FilesystemAdapter('app:v2', 0, $dir); new FilesystemAdapter('tenant/42', ...); passing a namespace containing a space or colon.

Common situations: Using a colon because it is conventional for Redis key prefixes; using a slash to namespace per-tenant; copying a namespace from a URL or env var that contains slashes.

Related errors


AI-assisted analysis of symfony/symfony@698e28026c (2026-08-06). Data as JSON: /api/errors/387911e7c81d0a15. Report an issue: GitHub.