{"record":{"id":"f00135cc1f8909e8","repo":"flarum/framework","slug":"the-prefix-may-only-contain-characters-and-underscores","errorCode":null,"errorMessage":"The prefix may only contain characters and underscores.","messagePattern":"The prefix may only contain characters and underscores\\.","errorType":"validation","errorClass":"ValidationFailed","httpStatus":null,"severity":"error","filePath":"framework/core/src/Install/DatabaseConfig.php","lineNumber":73,"sourceCode":"        if (($this->port < 1 || $this->port > 65535) && in_array($this->driver, ['mysql', 'mariadb', 'pgsql'])) {\n            throw new ValidationFailed('Please provide a valid port number between 1 and 65535.');\n        }\n\n        if (empty($this->database)) {\n            throw new ValidationFailed('Please specify the database name.');\n        }\n\n        if (empty($this->schema) && $this->driver == 'pgsql') {\n            throw new ValidationFailed('Please specify the schema name.');\n        }\n\n        if (empty($this->username) && in_array($this->driver, ['mysql', 'mariadb', 'pgsql'])) {\n            throw new ValidationFailed('Please specify the username for accessing the database.');\n        }\n\n        if (! empty($this->prefix)) {\n            if (! preg_match('/^[\\pL\\pM\\pN_]+$/u', $this->prefix)) {\n                throw new ValidationFailed('The prefix may only contain characters and underscores.');\n            }\n\n            $maxPrefix = DatabaseRequirements::maxTablePrefixLength($this->driver);\n\n            if ($maxPrefix !== null && strlen($this->prefix) > $maxPrefix) {\n                throw new ValidationFailed(\"The prefix should be no longer than $maxPrefix characters on $this->driver.\");\n            }\n        }\n    }\n\n    public function prepare(Paths $paths): void\n    {\n        if ($this->driver === 'sqlite' && ! file_exists($this->database)) {\n            $this->database = str_replace('.sqlite', '', $this->database).'.sqlite';\n            touch($paths->base.'/'.$this->database);\n        }\n    }\n","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/flarum/framework/blob/4b939f685389bfe8a380e9e28ddf305a1c66950c/framework/core/src/Install/DatabaseConfig.php#L55-L91","documentation":"ValidationFailed thrown by DatabaseConfig::validate when a non-empty table prefix contains characters outside Unicode letters, marks, numbers and underscores. The regex /^[\\pL\\pM\\pN_]+$/u enforces identifier-safe prefixes so prefixed table names stay valid SQL.","triggerScenarios":"Setting prefix to a value with hyphens, dots, spaces, or other symbols, e.g. 'my-app-', 'app.prefix', 'flarum '.","commonSituations":"Users copying a prefix from a URL or domain (my-site.com_); hyphenated project names; whitespace from pasted input; trying to namespace tables with dots.","solutions":["Remove invalid characters — use only letters, digits and underscores, e.g. 'myapp_'.","Replace hyphens/dots with underscores before constructing DatabaseConfig.","Trim the prefix; if you do not need one, leave it empty (empty prefix is allowed)."],"exampleFix":"// before\nnew DatabaseConfig(driver: 'mysql', host: 'db', port: 3306, database: 'app', prefix: 'my-app-');\n// after\nnew DatabaseConfig(driver: 'mysql', host: 'db', port: 3306, database: 'app', prefix: 'my_app_');","handlingStrategy":"validation","validationCode":"$prefix = trim($rawPrefix);\nif ($prefix !== '' && ! preg_match('/^[\\\\pL\\\\pM\\\\pN_]+$/u', $prefix)) {\n    $prefix = preg_replace('/[^\\\\pL\\\\pM\\\\pN_]/u', '_', $prefix);\n}\n$config = new DatabaseConfig(driver: $driver, host: $host, port: $port, database: $database, prefix: $prefix);","typeGuard":"function isValidPrefix(string $prefix): bool {\n    return $prefix === '' || preg_match('/^[\\\\pL\\\\pM\\\\pN_]+$/u', $prefix) === 1;\n}","tryCatchPattern":"try {\n    $config = new DatabaseConfig(...$input);\n} catch (ValidationFailed $e) {\n    if (str_contains($e->getMessage(), 'prefix may only')) {\n        $errors['prefix'] = 'Use only letters, numbers and underscores.';\n    }\n}","preventionTips":["Sanitize prefix input server-side with preg_replace before validation.","Add a client-side pattern attribute on the prefix input.","Never derive prefixes from domains or URLs without normalization."],"tags":["database","prefix","validation","sql"],"backgroundTag":"invalid-identifier-format","analyzedSha":"4b939f685389bfe8a380e9e28ddf305a1c66950c","analyzedAt":"2026-09-15T18:09:20.879Z","contentChangedAt":"2026-09-15T18:09:20.879Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}