Summary
GoogleBigQueryTools._run_sql() removes newline characters without preserving token boundaries, causing SQL line comments (–) to swallow the entire query. The silent error handler then returns an empty string, making failures appear as “0 rows returned.”
Affected Version
-
Agno v2.x (tested on v2.3.x)
-
File: agno/tools/google_bigquery.py, line 109
Root Cause
# Line 109 - current implementation
cleaned_query = sql.replace("\\n", " ").replace("\n", "").replace("\\", "")
The .replace(“\n”, “”) removes actual newlines without adding spaces. This breaks SQL line comments (–) which extend until the next newline character.
Reproduction Steps
-
Create an agent with GoogleBigQueryTools
-
Have the agent generate a query with a – comment:
query = """SELECT
p.product_id,
SUM(o.amount) AS revenue,
-- Calculate net after discounts
SUM(o.amount) - SUM(o.discount) AS net_revenue
FROM orders o
JOIN products p ON o.product_id = p.product_id
LIMIT 10"""
- Call run_sql_query(query)
Expected Behaviour
Query executes successfully, returning results.
Actual Behaviour
After _run_sql() processing, the query becomes:
SELECT p.product_id, SUM(o.amount) AS revenue, -- Calculate net after discounts SUM(o.amount) - SUM(o.discount) AS net_revenueFROM orders oJOIN products p ON o.product_id = p.product_idLIMIT 10
The – comment now extends to the end of the (single-line) query, commenting out:
-
SUM(o.amount) - SUM(o.discount) AS net_revenue
-
FROM orders o
-
JOIN products p ON o.product_id = p.product_id
-
LIMIT 10
BigQuery receives an incomplete SELECT statement → syntax error → exception caught → returns .
Secondary Issues
1. Silent Error Handler (Lines 115-117)
except Exception as e:
logger.error(f"Error while executing SQL: {e}")
return "" # Returns empty string, not error message
Agents interpret “” as “query returned 0 rows” rather than “query failed.”
2. Double Serialization (Lines 95 + 113-114)
# _run_sql() returns a string:
results_str = str([dict(row) for row in results])
return results_str
# run_sql_query() JSON-encodes that string:
return json.dumps(self._run_sql(sql=query), default=str)
This creates double-encoded output that may confuse LLM parsing.
Proposed Fix
# Line 109 - replace newlines with SPACES, not empty string
cleaned_query = sql.replace("\\n", " ").replace("\n", " ").replace("\\", "")
# ↑ SPACE instead of ""
# Lines 115-117 - return error message, not empty string
except Exception as e:
logger.error(f"Error while executing SQL: {e}")
return f"Error executing query: {e}"
Impact
- Severity: High - Any query with SQL comments silently fails