{"id":"528d2a2a5caaf943","repo":"laravel/framework","slug":"index-name-contains-invalid-characters","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/MySqlGrammar.php","lineNumber":153,"sourceCode":"\n    /**\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        $index = $indexHint->index;\n\n        $indexes = array_map('trim', explode(',', $index));\n\n        foreach ($indexes as $i) {\n            if (! preg_match('/^[a-zA-Z0-9_$]+$/', $i)) {\n                throw new InvalidArgumentException('Index name contains invalid characters.');\n            }\n        }\n\n        return match ($indexHint->type) {\n            'hint' => \"use index ({$index})\",\n            'force' => \"force index ({$index})\",\n            default => \"ignore index ({$index})\",\n        };\n    }\n\n    /**\n     * Compile a group limit clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return string\n     */\n    protected function compileGroupLimit(Builder $query)\n    {","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/laravel/framework/blob/bd6b5437e6ad87bb49f9b426724f07a9f64e9683/src/Illuminate/Database/Query/Grammars/MySqlGrammar.php#L135-L171","documentation":"MySqlGrammar::compileIndexHint() validates each comma-separated index name against the regex /^[a-zA-Z0-9_$]+$/ and throws InvalidArgumentException if any segment fails. MySQL index hints (USE/FORCE/IGNORE INDEX) require bare identifiers, so Laravel rejects names containing spaces, hyphens, dots, or quoting characters before emitting SQL.","triggerScenarios":"Calling useIndex($name), forceIndex($name), or ignoreIndex($name) on a MySQL/MariaDB query where $name contains characters outside [a-zA-Z0-9_$] (e.g. 'idx-name', 'my index', 'schema.idx'). Multi-index strings like 'a,b' are split and each segment validated.","commonSituations":"Generating index hint names dynamically from user input or config that may include hyphens/spaces. Mismatch between an index's actual database name and the string passed to the hint (e.g. quoting it).","solutions":["Pass the exact bare index name as it exists in MySQL (letters, digits, underscore, dollar only).","Sanitize the index name before passing it: strip or replace invalid characters.","If the index truly has special characters, reference it via a raw query snippet instead of the index hint API."],"exampleFix":"// before\n$query->from('users')->forceIndex('idx-last-name');\n\n// after (use the real bare index name)\n$query->from('users')->forceIndex('idx_last_name');","handlingStrategy":"validation","validationCode":"$index = 'idx_last_name';\nif (! preg_match('/^[a-zA-Z0-9_$]+$/', $index)) {\n    throw new \\InvalidArgumentException(\"Invalid MySQL index name: {$index}\");\n}\n$query->from('users')->forceIndex($index);","typeGuard":"function isValidMysqlIndexName(string $name): bool\n{\n    foreach (explode(',', $name) as $segment) {\n        if (! preg_match('/^[a-zA-Z0-9_$]+$/', trim($segment))) {\n            return false;\n        }\n    }\n    return true;\n}","tryCatchPattern":null,"preventionTips":["Use underscores, never hyphens/spaces, in index names.","Validate user-supplied index names before passing to hint methods.","Keep a constant/enum of known index names instead of building them dynamically."],"tags":["index-hint","mysql","validation","invalid-characters"],"analyzedSha":"bd6b5437e6ad87bb49f9b426724f07a9f64e9683","analyzedAt":"2026-08-06T00:28:32.783Z","schemaVersion":2}