crewAIInc/crewAI · error · ValueError

MySQL table_name must be a valid table identifier or schema.

Error message

MySQL table_name must be a valid table identifier or schema.table identifier

What it means

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.

Source

Thrown at lib/crewai-tools/src/crewai_tools/tools/mysql_search_tool/mysql_search_tool.py:22

from pydantic import BaseModel, Field

from crewai_tools.rag.data_types import DataType
from crewai_tools.tools.rag.rag_tool import RagTool


_MYSQL_IDENTIFIER_PATTERN = re.compile(r"^[A-Za-z_][A-Za-z0-9_$]*$")


def _quote_mysql_table_name(table_name: str) -> str:
    identifier_parts = table_name.split(".")
    if (
        not identifier_parts
        or len(identifier_parts) > 2
        or any(
            not _MYSQL_IDENTIFIER_PATTERN.fullmatch(part) for part in identifier_parts
        )
    ):
        raise ValueError(
            "MySQL table_name must be a valid table identifier or schema.table "
            "identifier"
        )

    return ".".join(f"`{part}`" for part in identifier_parts)


class MySQLSearchToolSchema(BaseModel):
    """Input for MySQLSearchTool."""

    search_query: str = Field(
        ...,
        description="Mandatory semantic search query you want to use to search the database's content",
    )


class MySQLSearchTool(RagTool):
    name: str = "Search a database's table content"

View on GitHub (pinned to 754d7323be)

Solutions

  1. Pass a bare identifier: MySQLSearchTool(table_name="users") or "schema.users"
  2. For names with special characters, the validator forbids them — rename the table or use a view with a safe name
  3. Strip accidental whitespace: table_name.strip() before constructing the tool

Example fix

# before
tool = MySQLSearchTool(table_name="my-db.my-table")  # ValueError

# after
tool = MySQLSearchTool(table_name="my_db.my_table")  # underscore, one dot max
Defensive patterns

Strategy: validation

Validate before calling

import re

_MYSQL_IDENT = re.compile(r"^[A-Za-z_][A-Za-z0-9_$]*$")

def valid_mysql_table_name(name: str) -> bool:
    parts = name.strip().split(".")
    return 1 <= len(parts) <= 2 and all(_MYSQL_IDENT.fullmatch(p) for p in parts)

Type guard

def is_valid_mysql_table_name(name: str) -> bool:
    parts = name.strip().split(".")
    return 1 <= len(parts) <= 2 and all(
        __import__("re").fullmatch(r"[A-Za-z_][A-Za-z0-9_$]*", p) for p in parts
    )

Try / catch

try:
    tool = MySQLSearchTool(table_name=name)
except ValueError as e:
    if "valid table identifier" in str(e):
        raise ValueError(
            f"{name!r} is not schema.table-safe; use bare identifiers only"
        ) from e
    raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15). Data as JSON: /api/errors/ee1a8ddd151bf9a7. Report an issue: GitHub.