{"id":"0773d9d928ddd9e6","repo":"laravel/framework","slug":"index-name-contains-invalid-characters-0773d9","errorCode":null,"errorMessage":"Index name contains invalid characters.","messagePattern":"Index name contains invalid characters\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php","lineNumber":185,"sourceCode":"    /**\n     * Compile the index hints for the query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  \\Illuminate\\Database\\Query\\IndexHint  $indexHint\n     * @return string\n     *\n     * @throws \\InvalidArgumentException\n     */\n    protected function compileIndexHint(Builder $query, $indexHint)\n    {\n        if ($indexHint->type !== 'force') {\n            return '';\n        }\n\n        $index = $indexHint->index;\n\n        if (! preg_match('/^[a-zA-Z0-9_$]+$/', $index)) {\n            throw new InvalidArgumentException('Index name contains invalid characters.');\n        }\n\n        return \"indexed by {$index}\";\n    }\n\n    /**\n     * Compile a \"JSON length\" statement into SQL.\n     *\n     * @param  string  $column\n     * @param  string  $operator\n     * @param  string  $value\n     * @return string\n     */\n    protected function compileJsonLength($column, $operator, $value)\n    {\n        [$field, $path] = $this->wrapJsonFieldAndPath($column);\n\n        return 'json_array_length('.$field.$path.') '.$operator.' '.$value;","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/laravel/framework/blob/bd6b5437e6ad87bb49f9b426724f07a9f64e9683/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php#L167-L203","documentation":"SQLiteGrammar::compileIndexHint() throws InvalidArgumentException when a force-type hint's index name fails the regex /^[a-zA-Z0-9_$]+$/. SQLite only supports INDEXED BY for forced index usage, so only forceIndex() is validated; use/ignore hints return an empty string and are skipped.","triggerScenarios":"Calling forceIndex($name) on a SQLite connection where $name contains characters outside [a-zA-Z0-9_$] (hyphen, space, dot, quotes). useIndex/ignoreIndex do not throw on SQLite because they compile to nothing.","commonSituations":"Sharing index-hint code between MySQL and SQLite tests where the index name format differs. Passing a quoted or dotted index identifier to forceIndex on SQLite.","solutions":["Use the bare SQLite index name containing only [a-zA-Z0-9_$].","Avoid forceIndex on SQLite in tests, or guard it behind a driver check.","Rename the index to use underscores instead of hyphens/spaces."],"exampleFix":"// before\n$query->from('users')->forceIndex('idx-email-lookup');\n\n// after\n$query->from('users')->forceIndex('idx_email_lookup');","handlingStrategy":"validation","validationCode":"// SQLite only validates force-type hints\nif ($query->getConnection()->getDriverName() === 'sqlite' && $hintType === 'force') {\n    if (! preg_match('/^[a-zA-Z0-9_$]+$/', $index)) {\n        throw new \\InvalidArgumentException(\"Invalid SQLite index name: {$index}\");\n    }\n}\n$query->from('users')->forceIndex($index);","typeGuard":"function isValidSqliteIndexName(string $name): bool\n{\n    return (bool) preg_match('/^[a-zA-Z0-9_$]+$/', $name);\n}","tryCatchPattern":null,"preventionTips":["Use underscore-only index names for cross-engine compatibility.","Skip forceIndex on SQLite in tests when not essential.","Maintain a single naming convention for index identifiers."],"tags":["index-hint","sqlite","validation","invalid-characters"],"analyzedSha":"bd6b5437e6ad87bb49f9b426724f07a9f64e9683","analyzedAt":"2026-08-06T00:28:32.783Z","schemaVersion":2}