{"record":{"id":"ee1a8ddd151bf9a7","repo":"crewAIInc/crewAI","slug":"mysql-table-name-must-be-a-valid-table-identifier","errorCode":null,"errorMessage":"MySQL table_name must be a valid table identifier or schema.table identifier","messagePattern":"MySQL table_name must be a valid table identifier or schema\\.table identifier","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"lib/crewai-tools/src/crewai_tools/tools/mysql_search_tool/mysql_search_tool.py","lineNumber":22,"sourceCode":"from pydantic import BaseModel, Field\n\nfrom crewai_tools.rag.data_types import DataType\nfrom crewai_tools.tools.rag.rag_tool import RagTool\n\n\n_MYSQL_IDENTIFIER_PATTERN = re.compile(r\"^[A-Za-z_][A-Za-z0-9_$]*$\")\n\n\ndef _quote_mysql_table_name(table_name: str) -> str:\n    identifier_parts = table_name.split(\".\")\n    if (\n        not identifier_parts\n        or len(identifier_parts) > 2\n        or any(\n            not _MYSQL_IDENTIFIER_PATTERN.fullmatch(part) for part in identifier_parts\n        )\n    ):\n        raise ValueError(\n            \"MySQL table_name must be a valid table identifier or schema.table \"\n            \"identifier\"\n        )\n\n    return \".\".join(f\"`{part}`\" for part in identifier_parts)\n\n\nclass MySQLSearchToolSchema(BaseModel):\n    \"\"\"Input for MySQLSearchTool.\"\"\"\n\n    search_query: str = Field(\n        ...,\n        description=\"Mandatory semantic search query you want to use to search the database's content\",\n    )\n\n\nclass MySQLSearchTool(RagTool):\n    name: str = \"Search a database's table content\"","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/crewAIInc/crewAI/blob/754d7323beb2fd042e33444a115ea2d5a47193f0/lib/crewai-tools/src/crewai_tools/tools/mysql_search_tool/mysql_search_tool.py#L4-L40","documentation":"MySQLSearchTool quotes the user-supplied table name into backticks after validating each dot-separated part against ^[A-Za-z_][A-Za-z0-9_$]*$. This ValueError fires when the name is not a bare identifier or schema.table: more than one dot, empty part, leading digit, spaces, hyphens, backticks, or other characters. It is primarily a SQL-injection guard that rejects anything it cannot safely quote.","triggerScenarios":"Passing table_name=\"my-table\" (hyphen), \"db.schema.table\" (two dots), \"1table\" (leading digit), \"`users`\" (pre-quoted), or \"public .users\" (spaces); passing a subquery or table name with whitespace/newlines.","commonSituations":"Table names with hyphens created outside the app; users trying to pre-quote with backticks; copy-pasted names with hidden whitespace; attempts to pass raw SQL fragments.","solutions":["Pass a bare identifier: MySQLSearchTool(table_name=\"users\") or \"schema.users\"","For names with special characters, the validator forbids them — rename the table or use a view with a safe name","Strip accidental whitespace: table_name.strip() before constructing the tool"],"exampleFix":"# before\ntool = MySQLSearchTool(table_name=\"my-db.my-table\")  # ValueError\n\n# after\ntool = MySQLSearchTool(table_name=\"my_db.my_table\")  # underscore, one dot max","handlingStrategy":"validation","validationCode":"import re\n\n_MYSQL_IDENT = re.compile(r\"^[A-Za-z_][A-Za-z0-9_$]*$\")\n\ndef valid_mysql_table_name(name: str) -> bool:\n    parts = name.strip().split(\".\")\n    return 1 <= len(parts) <= 2 and all(_MYSQL_IDENT.fullmatch(p) for p in parts)","typeGuard":"def is_valid_mysql_table_name(name: str) -> bool:\n    parts = name.strip().split(\".\")\n    return 1 <= len(parts) <= 2 and all(\n        __import__(\"re\").fullmatch(r\"[A-Za-z_][A-Za-z0-9_$]*\", p) for p in parts\n    )","tryCatchPattern":"try:\n    tool = MySQLSearchTool(table_name=name)\nexcept ValueError as e:\n    if \"valid table identifier\" in str(e):\n        raise ValueError(\n            f\"{name!r} is not schema.table-safe; use bare identifiers only\"\n        ) from e\n    raise","preventionTips":["Pass bare identifiers only — never pre-quoted or hyphenated names","Validate user-supplied table names with the same regex before building tools","Create safe-named views over awkward legacy table names"],"tags":["mysql","sql-injection","validation","identifier","crewai-tools"],"backgroundTag":null,"analyzedSha":"754d7323beb2fd042e33444a115ea2d5a47193f0","analyzedAt":"2026-08-15T04:06:56.746Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}