{"record":{"id":"837276eb8cbf2c6c","repo":"symfony/symfony","slug":"namespace-contains-s-but-only-characters-in-837276","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/Adapter/PdoAdapter.php","lineNumber":64,"sourceCode":"     *  * db_data_col: The column where to store the cache data [default: item_data]\n     *  * db_lifetime_col: The column where to store the lifetime [default: item_lifetime]\n     *  * db_time_col: The column where to store the timestamp [default: item_time]\n     *  * db_username: The username when lazy-connect [default: '']\n     *  * db_password: The password when lazy-connect [default: '']\n     *  * db_connection_options: An array of driver-specific connection options [default: []]\n     *\n     * @throws InvalidArgumentException When first argument is not PDO nor Connection nor string\n     * @throws InvalidArgumentException When PDO error mode is not PDO::ERRMODE_EXCEPTION\n     * @throws InvalidArgumentException When namespace contains invalid characters\n     */\n    public function __construct(#[\\SensitiveParameter] \\PDO|string $connOrDsn, string $namespace = '', int $defaultLifetime = 0, array $options = [], ?MarshallerInterface $marshaller = null)\n    {\n        if (\\is_string($connOrDsn) && str_contains($connOrDsn, '://')) {\n            throw new InvalidArgumentException(\\sprintf('Usage of Doctrine DBAL URL with \"%s\" is not supported. Use a PDO DSN or \"%s\" instead.', __CLASS__, DoctrineDbalAdapter::class));\n        }\n\n        if (isset($namespace[0]) && 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\n        if ($connOrDsn instanceof \\PDO) {\n            if (\\PDO::ERRMODE_EXCEPTION !== $connOrDsn->getAttribute(\\PDO::ATTR_ERRMODE)) {\n                throw new InvalidArgumentException(\\sprintf('\"%s\" requires PDO error mode attribute be set to throw Exceptions (i.e. $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION)).', __CLASS__));\n            }\n\n            $this->conn = $connOrDsn;\n        } else {\n            $this->dsn = $connOrDsn;\n        }\n\n        $this->maxIdLength = self::MAX_KEY_LENGTH;\n        $this->table = $options['db_table'] ?? $this->table;\n        $this->idCol = $options['db_id_col'] ?? $this->idCol;\n        $this->dataCol = $options['db_data_col'] ?? $this->dataCol;\n        $this->lifetimeCol = $options['db_lifetime_col'] ?? $this->lifetimeCol;\n        $this->timeCol = $options['db_time_col'] ?? $this->timeCol;","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/symfony/symfony/blob/698e28026c22cf35d032cdb6e800db48b1535790/src/Symfony/Component/Cache/Adapter/PdoAdapter.php#L46-L82","documentation":"Thrown by PdoAdapter's constructor (PdoAdapter.php:63) when the $namespace contains any character outside [-+.A-Za-z0-9]. Like DoctrineDbalAdapter, the namespace is interpolated into raw SQL LIKE patterns for clear/fetch, so unsafe characters are rejected to prevent query breakage and injection.","triggerScenarios":"Calling `new PdoAdapter($dsn, 'my cache')` (space), `new PdoAdapter($dsn, 'a_b')` (underscore), or any namespace with slash/colon/etc. The regex '#[^-+.A-Za-z0-9]#' catches the first offender.","commonSituations":"Using a tenant id or app name with underscores/spaces as the cache namespace. Auto-derived namespaces from user input. Copying a namespace format used by a different adapter that allows underscores.","solutions":["Restrict the namespace to [-+.A-Za-z0-9] characters.","Sanitize dynamic namespaces: $ns = preg_replace('/[^-+.A-Za-z0-9]/', '', $raw);","Use dots or pluses for hierarchical separation instead of underscores/slashes."],"exampleFix":"// before\nnew PdoAdapter($dsn, 'order_cache/v2');\n\n// after\nnew PdoAdapter($dsn, 'order.cache.v2');","handlingStrategy":"validation","validationCode":"if (preg_match('#[^-+.A-Za-z0-9]#', $namespace, $m)) {\n    throw new \\InvalidArgumentException('Invalid cache namespace char: '.$m[0]);\n}\nnew PdoAdapter($dsn, $namespace);","typeGuard":"function isValidCacheNamespace(string $ns): bool\n{\n    return '' === $ns || 1 === preg_match('#^[-+.A-Za-z0-9]*$#', $ns);\n}","tryCatchPattern":null,"preventionTips":["Sanitize tenant/app-derived namespaces: preg_replace('/[^-+.A-Za-z0-9]/', '', $raw).","Use dots or hyphens for hierarchy, never slashes or underscores.","Unit-test namespace inputs against the allowed character class."],"tags":["cache","pdo","namespace","validation","sql-injection"],"analyzedSha":"698e28026c22cf35d032cdb6e800db48b1535790","analyzedAt":"2026-08-06T23:40:49.025Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}