{"record":{"id":"87c37c7c337bb6b1","repo":"run-llama/llama_index","slug":"statement-command-r-is-invalid-sql-nerror-exc","errorCode":null,"errorMessage":"Statement {command!r} is invalid SQL.\\nError: {exc.orig}","messagePattern":"Statement (.+?) is invalid SQL\\.\\\\nError: (.+?)","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"llama-index-core/llama_index/core/utilities/sql_wrapper.py","lineNumber":262,"sourceCode":"            _replace,\n            command,\n            flags=re.IGNORECASE,\n        )\n\n    def run_sql(self, command: str) -> Tuple[str, Dict]:\n        \"\"\"\n        Execute a SQL statement and return a string representing the results.\n\n        If the statement returns rows, a string of the results is returned.\n        If the statement returns no rows, an empty string is returned.\n        \"\"\"\n        with self._engine.begin() as connection:\n            try:\n                if self._schema:\n                    command = self._add_schema_prefix(command)\n                cursor = connection.execute(text(command))\n            except (ProgrammingError, OperationalError) as exc:\n                raise NotImplementedError(\n                    f\"Statement {command!r} is invalid SQL.\\nError: {exc.orig}\"\n                ) from exc\n            if cursor.returns_rows:\n                result = cursor.fetchall()\n                # truncate the results to the max string length\n                # we can't use str(result) directly because it automatically truncates long strings\n                truncated_results = []\n                for row in result:\n                    # truncate each column, then convert the row to a tuple\n                    truncated_row = tuple(\n                        self.truncate_word(column, length=self._max_string_length)\n                        for column in row\n                    )\n                    truncated_results.append(truncated_row)\n                return str(truncated_results), {\n                    \"result\": truncated_results,\n                    \"col_keys\": list(cursor.keys()),\n                }","sourceCodeStart":244,"sourceCodeEnd":280,"githubUrl":"https://github.com/run-llama/llama_index/blob/afd0fef371831f9bda13e5af7167cf4e981278ab/llama-index-core/llama_index/core/utilities/sql_wrapper.py#L244-L280","documentation":"SQLWrapper.run_sql() (called by SQLTableRetrieverQueryEngine / NLSQLRetriever when executing model-generated SQL) wraps SQLAlchemy ProgrammingError and OperationalError in NotImplementedError, echoing the offending statement and the driver's original error. Despite the exception type, it means 'this SQL statement failed to execute' - usually invalid SQL produced by the LLM, a missing table/column, or a permissions problem.","triggerScenarios":"A text-to-SQL query engine executing an LLM-generated statement with wrong syntax, referencing include-filtered tables, or hitting dialect-specific errors (e.g. quoting, functions unsupported by SQLite). The raise happens inside engine.begin() so the transaction rolls back.","commonSituations":"Agents running NLSQLRetriever/SQLTableRetrieverQueryEngine against strict dialects (SQLite, BigQuery); schemas where some tables were excluded via include_tables but the model still references them; models confusing dialects (MySQL backticks on Postgres).","solutions":["Catch the exception and re-prompt the agent with the error text plus get_table_info() output so the model can self-correct (the standard self-correcting SQL agent pattern).","Log the SQL and run it manually to identify the exact syntax/permission problem.","Improve the schema context passed to the LLM (table info, sample rows, dialect note) to reduce invalid SQL generation.","If the error is permissions-related, grant the DB user access to the referenced tables."],"exampleFix":"# before (agent crashes on bad LLM SQL)\n response = query_engine.query('how many users signed up last week?')\n\n# after (self-correcting retry)\nfrom llama_index.core.utilities.sql_wrapper import SQLWrapper\n\ntry:\n    response = query_engine.query(q)\nexcept NotImplementedError as e:\n    corrected = agent.chat(\n        f'This SQL failed: {e}. Schema:\\n{db.get_table_info()}\\nRewrite and answer: {q}'\n    )","handlingStrategy":"try-catch","validationCode":"import sqlglot\n\ndef sql_is_parseable(command: str, dialect: str = 'sqlite') -> bool:\n    try:\n        sqlglot.parse_one(command, read=dialect)\n        return True\n    except sqlglot.errors.ParseError:\n        return False\n\n# guard LLM output before execution:\n# if not sql_is_parseable(sql): re-prompt the model","typeGuard":null,"tryCatchPattern":"try:\n    result = db.run_sql(sql)\nexcept NotImplementedError as e:\n    # feed the error back to the LLM for self-correction\n    sql = agent.chat(\n        f'SQL failed with: {e}\\nSchema:\\n{db.get_table_info()}\\nRewrite the SQL.'\n    )\n    result = db.run_sql(sql)","preventionTips":["Wrap every query_engine.query()/run_sql call in try/except NotImplementedError with a re-prompt loop (cap retries).","Include get_table_info() and the SQL dialect in the prompt to reduce invalid SQL.","Use a read-only DB user so bad LLM SQL cannot mutate data.","Parse-check generated SQL with sqlglot before executing when the model is unreliable."],"tags":["sql","text-to-sql","sqlalchemy","llm-output-validation"],"backgroundTag":null,"analyzedSha":"afd0fef371831f9bda13e5af7167cf4e981278ab","analyzedAt":"2026-08-15T05:42:58.429Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}