{"record":{"id":"387911e7c81d0a15","repo":"symfony/symfony","slug":"namespace-contains-s-but-only-characters-in-387911","errorCode":null,"errorMessage":"Namespace contains \"%s\" but only characters in [-+_.A-Za-z0-9] are allowed.","messagePattern":"Namespace contains \"(.+?)\" but only characters in \\[-\\+_\\.A-Za-z0-9\\] are allowed\\.","errorType":"exception","errorClass":"Symfony\\Component\\Cache\\Exception\\InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php","lineNumber":35,"sourceCode":" * @author Nicolas Grekas <p@tchwork.com>\n *\n * @internal\n */\ntrait FilesystemCommonTrait\n{\n    private string $directory;\n    private string $tmpSuffix;\n\n    private function init(string $namespace, ?string $directory): void\n    {\n        if (!isset($directory[0])) {\n            $directory = sys_get_temp_dir().\\DIRECTORY_SEPARATOR.'symfony-cache';\n        } else {\n            $directory = realpath($directory) ?: $directory;\n        }\n        if (isset($namespace[0])) {\n            if (preg_match('#[^-+_.A-Za-z0-9]#', $namespace, $match)) {\n                throw new InvalidArgumentException(\\sprintf('Namespace contains \"%s\" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0]));\n            }\n            $directory .= \\DIRECTORY_SEPARATOR.$namespace;\n        } else {\n            $directory .= \\DIRECTORY_SEPARATOR.'@';\n        }\n        if (!is_dir($directory)) {\n            @mkdir($directory, 0o777, true);\n        }\n        $directory .= \\DIRECTORY_SEPARATOR;\n        // On Windows the whole path is limited to 258 chars\n        if ('\\\\' === \\DIRECTORY_SEPARATOR && \\strlen($directory) > 234) {\n            throw new InvalidArgumentException(\\sprintf('Cache directory too long (%s).', $directory));\n        }\n\n        $this->directory = $directory;\n    }\n\n    protected function doClear(string $namespace): bool","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/symfony/symfony/blob/698e28026c22cf35d032cdb6e800db48b1535790/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php#L17-L53","documentation":"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.","triggerScenarios":"new FilesystemAdapter('app:v2', 0, $dir); new FilesystemAdapter('tenant/42', ...); passing a namespace containing a space or colon.","commonSituations":"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.","solutions":["Restrict the namespace to [-+_.A-Za-z0-9] (use - or _ as separators).","Hash or slugify arbitrary input: preg_replace('#[^-+_.A-Za-z0-9]#', '_', $input).","For per-tenant separation that needs '/', rely on the adapter's own hashed sharding instead of the namespace."],"exampleFix":"// before\nnew FilesystemAdapter('tenant:42', 0, $dir);\n\n// after\nnew FilesystemAdapter('tenant_42', 0, $dir);","handlingStrategy":"validation","validationCode":"$ns = preg_replace('#[^-+_.A-Za-z0-9]#', '_', $rawNamespace);\nnew FilesystemAdapter($ns, 0, $dir);","typeGuard":"function isValidNamespace(string $ns): bool {\n    return preg_match('#^[^-+_.A-Za-z0-9]*$#', $ns) || !preg_match('#[^-+_.A-Za-z0-9]#', $ns);\n}","tryCatchPattern":null,"preventionTips":["Restrict namespaces to [-+_.A-Za-z0-9].","Slugify tenant-derived namespaces before use.","Reject slashes/colons at the config layer."],"tags":["filesystem","namespace","validation","cache"],"analyzedSha":"698e28026c22cf35d032cdb6e800db48b1535790","analyzedAt":"2026-08-06T23:40:49.025Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}