zylon-ai/private-gpt · error · ValueError
Invalid CALL statement format
Error message
Invalid CALL statement format
What it means
Thrown by _parse_call_statement in database_query_generator.py when the regex 'CALL\s+([\w.]+)\s*\((.*?)\)' fails to match the query text. The generator only understands stored-procedure invocations of the exact form CALL schema.proc(args...), and re-parses the LLM-generated SQL to extract the procedure name, parameter values, and OUT-parameter positions. Any deviation in syntax (missing parens, empty CALL, malformed spacing that breaks the pattern) makes the parse fail and raises this ValueError.
Source
Thrown at private_gpt/components/tabular/database_query_generator.py:1278
except Exception as e:
return QueryResult(
query=call_statement,
error=ErrorQueryResult(
description=f"DB2 procedure execution failed: {mask_connection_secrets(str(e))}",
type=ErrorType.UNKNOWN,
),
row_count=-1,
)
def _parse_call_statement(
self, call_statement: str
) -> tuple[str, list[str | int], list[int]]:
match = re.search(
r"CALL\s+([\w.]+)\s*\((.*?)\)", call_statement, re.IGNORECASE | re.DOTALL
)
if not match:
raise ValueError("Invalid CALL statement format")
proc_name = match.group(1)
params_str = match.group(2)
param_values: list[str | int] = []
out_indices: list[int] = []
for i, param in enumerate(params_str.split(",")):
param = param.strip()
if param == "?":
param_values.append(0) # Default value for OUT parameters
out_indices.append(i)
else:
param_values.append(param.strip("'\""))
return proc_name, param_values, out_indices
def _create_db2_connection(self) -> Any:View on GitHub (pinned to 4a030776a3)
Solutions
- Log the exact call_statement that failed to parse and inspect it for syntax the regex cannot match (missing parens, quoted identifiers, BEGIN/COMMIT wrappers).
- Tighten the prompt/few-shot at line 773 so the model emits exactly 'CALL schema.proc_name(arg1, ?, ?, ?);' with nothing else.
- Normalize the statement before parsing: strip trailing semicolons, leading BEGIN/COMMIT, and collapse whitespace.
- Extend the regex to allow quoted identifiers, e.g. r"CALL\s+(?:[\w.]+|\"[^\"]+\")\s*\((.*?)\)".
- Wrap the parse in a retry that asks the LLM to regenerate the CALL statement when a QuerySyntaxError/ValueError is raised.
Example fix
# before
match = re.search(
r"CALL\s+([\w.]+)\s*\((.*?)\)", call_statement, re.IGNORECASE | re.DOTALL
)
if not match:
raise ValueError("Invalid CALL statement format")
# after
normalized = re.sub(r"^(BEGIN|COMMIT)\s*;?\s*", "", call_statement.strip(), flags=re.IGNORECASE).strip().rstrip(";").strip()
match = re.search(
r"CALL\s+([\w.]+)\s*\((.*?)\)", normalized, re.IGNORECASE | re.DOTALL
)
if not match:
logger.error("Unparseable CALL statement: %r", call_statement)
raise ValueError("Invalid CALL statement format") Defensive patterns
Strategy: validation
Validate before calling
import re
CALL_RE = re.compile(r"CALL\s+([\w.]+)\s*\((.*?)\)", re.IGNORECASE | re.DOTALL)
def is_parseable_call(stmt: str) -> bool:
stmt = stmt.strip().rstrip(';').strip()
return bool(CALL_RE.search(stmt))
# before the generator call:
# assert is_parseable_call(llm_query), f"bad CALL statement: {llm_query!r}" Try / catch
try:
row_count = generator.get_row_count(result)
except ValueError as e:
if "Invalid CALL statement format" in str(e):
# regenerate the SQL with corrective feedback
result = regenerate_sql(prompt_with_error(str(e)))
else:
raise Prevention
- Pin few-shot examples so the model always emits 'CALL schema.proc(arg, ?, ?, ?);'
- Normalize whitespace/semicolons and strip BEGIN/COMMIT before parsing
- Reject quoted procedure identifiers at generation time or extend the regex deliberately
When it happens
Trigger: An LLM-generated query string passed to the row-count/result path (line 1239) does not literally start with or contain 'CALL proc(...)'. Examples: the model emits 'CALL proc' with no parentheses, wraps the call in BEGIN/COMMIT despite the prompt instruction, returns prose or an empty string, or uses a quoted procedure name like CALL "my proc"(...) whose spaces break the [\w.]+ capture.
Common situations: Prompt-regression after changing the few-shot examples at line 773; models that add semicolons inside the parens or emit multiple statements; older stored procedures with uppercase/lowercase mix (handled) vs. quoted identifiers (not handled); an empty params string 'CALL p()' actually matches (group 2 is empty) but 'CALL p' does not.
Related errors
- Failed to parse JSON: {e!s}
- Failed to execute some SQL queries: {', '.join(str(e) for e
- Query not found: {sql_query}
- Empty response from generator.
- Generator did not return valid JSON.
AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15).
Data as JSON: /api/errors/e4d973f7fef8be54.
Report an issue: GitHub.