{"record":{"id":"3209aad73aef9e91","repo":"crewAIInc/crewAI","slug":"nl2sqltool-received-an-empty-sql-query","errorCode":null,"errorMessage":"NL2SQLTool received an empty SQL query.","messagePattern":"NL2SQLTool received an empty SQL query\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"warning","filePath":"lib/crewai-tools/src/crewai_tools/tools/nl2sql/nl2sql_tool.py","lineNumber":305,"sourceCode":"\n        self.tables = tables\n        self.columns = data\n\n    # Query validation\n\n    def _validate_query(self, sql_query: str) -> None:\n        \"\"\"Raise ValueError if *sql_query* is not permitted under the current config.\n\n        Splits the query on semicolons and validates each statement\n        independently.  When ``allow_dml=False`` (the default), multi-statement\n        queries are rejected outright to prevent ``SELECT 1; DROP TABLE users``\n        style bypasses.  When ``allow_dml=True`` every statement is checked and\n        a warning is emitted for write operations.\n        \"\"\"\n        statements = [s.strip() for s in sql_query.split(\";\") if s.strip()]\n\n        if not statements:\n            raise ValueError(\"NL2SQLTool received an empty SQL query.\")\n\n        if not self.allow_dml and len(statements) > 1:\n            raise ValueError(\n                \"NL2SQLTool blocked a multi-statement query in read-only mode. \"\n                \"Semicolons are not permitted when allow_dml=False.\"\n            )\n\n        for stmt in statements:\n            self._validate_statement(stmt)\n\n    def _validate_statement(self, stmt: str) -> None:\n        \"\"\"Validate a single SQL statement (no semicolons).\"\"\"\n        command = self._extract_command(stmt)\n\n        # EXPLAIN ANALYZE / EXPLAIN ANALYSE actually *executes* the underlying\n        # query.  Resolve the real command so write operations are caught.\n        # parenthesized (\"EXPLAIN (ANALYZE) DELETE …\", \"EXPLAIN (ANALYZE, VERBOSE) DELETE …\").\n        # EXPLAIN ANALYZE actually executes the underlying query — resolve the","sourceCodeStart":287,"sourceCodeEnd":323,"githubUrl":"https://github.com/crewAIInc/crewAI/blob/754d7323beb2fd042e33444a115ea2d5a47193f0/lib/crewai-tools/src/crewai_tools/tools/nl2sql/nl2sql_tool.py#L287-L323","documentation":"NL2SQLTool._validate_query splits the submitted sql_query on semicolons and discards empty fragments; if nothing remains, the query was empty or only whitespace/semicolons, and a ValueError is raised. This guards the executor against empty statements before touching the database.","triggerScenarios":"Calling the tool (or _run) with sql_query=\"\", sql_query=\"   \", or sql_query=\";;;\". Typically an LLM agent emits an empty string because it put the SQL in the wrong field or failed to generate a query.","commonSituations":"Agent produces an empty tool call argument; upstream prompt/variable interpolation yields an empty string; a templating bug passes the placeholder name instead of its value.","solutions":["Log the raw sql_query the agent actually sent and fix the prompt/template so a real SQL statement is passed.","Reject empty queries in your own code before invoking the tool.","If the agent may legitimately have nothing to ask, add an early branch that skips the tool call."],"exampleFix":"# before\ntool._run(\"\")\n\n# after\nif not sql_query or not sql_query.strip(\"; \\t\\n\"):\n    raise ValueError(\"refusing to run empty SQL\")\ntool._run(sql_query)","handlingStrategy":"validation","validationCode":"def has_statement(sql: str) -> bool:\n    return any(s.strip() for s in sql.split(\";\"))\n\nif not has_statement(sql_query):\n    raise ValueError(\"no SQL statement to run\")","typeGuard":"def is_non_empty_sql(sql: str | None) -> bool:\n    return isinstance(sql, str) and bool(sql.strip(\"; \\t\\r\\n\"))","tryCatchPattern":"try:\n    tool._run(sql_query)\nexcept ValueError as e:\n    if \"empty SQL query\" in str(e):\n        # ask the agent to regenerate the query\n        ...","preventionTips":["Check sql_query.strip() before invoking the tool.","Validate agent tool-call args against NL2SQLToolInput (pydantic) with min_length on sql_query.","Log raw agent arguments when a tool call fails to spot interpolation bugs."],"tags":["nl2sql","validation","empty-input","sql"],"backgroundTag":null,"analyzedSha":"754d7323beb2fd042e33444a115ea2d5a47193f0","analyzedAt":"2026-08-15T04:06:56.746Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}