Skip to content

Query Errors

deep_db_agents.query_errors

Turns query execution exceptions into feedback for the agent.

When the LLM generates an invalid query (syntax error, non-existent table/column/field, incompatible operator or type, ...), the database driver raises an exception. Instead of propagating it opaquely — interrupting the agent's turn — the tools convert it into a structured message the agent can read to fix the query on the next attempt: error handling becomes part of the feedback loop, not a terminal failure.

Whitelist/scope violations (QueryNotAllowedError: out-of-scope index/collection, disallowed stage or write clauses, malformed query) also flow through here and become feedback: the forbidden operation is still not executed — it is blocked before reaching the driver — but the rejection is communicated to the agent as a corrective message rather than interrupting the turn. The EXPLAIN row-estimate guardrail (EstimateExceededError) is handled the same way by format_estimate_block: the query is not executed, but the agent is asked to refine or aggregate and retry. The session row budget (RowBudgetExceededError from SessionBudget) is likewise turned into feedback by format_budget_block: the query did run, but its result is not returned, and the agent is asked to aggregate/summarize or start a new session.

format_budget_block

format_budget_block(exc: RowBudgetExceededError, *, what: str = 'query') -> str

Format a session row-budget exhaustion as corrective feedback.

Turns the RowBudgetExceededError raised by SessionBudget.charge into a message the agent can act on: the query did run, but its result is not returned because the cumulative session row budget is exhausted, so the agent should aggregate/summarize in the database or start a new session instead of extracting more rows.

Parameters:

Name Type Description Default
exc RowBudgetExceededError

The guardrail exception raised when the budget was exceeded; its message already describes the consumed rows and the budget.

required
what str

Label for the blocked construct ("query", "search", ...), used in the message.

'query'

Returns:

Name Type Description
str str

A message describing the block, suitable for returning to the agent as tool

str

output.

Source code in src/deep_db_agents/query_errors.py
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
def format_budget_block(exc: RowBudgetExceededError, *, what: str = "query") -> str:
    """Format a session row-budget exhaustion as corrective feedback.

    Turns the ``RowBudgetExceededError`` raised by ``SessionBudget.charge`` into a message
    the agent can act on: the query did run, but its result is **not returned** because the
    cumulative session row budget is exhausted, so the agent should aggregate/summarize in
    the database or start a new session instead of extracting more rows.

    Args:
        exc: The guardrail exception raised when the budget was exceeded; its message already
            describes the consumed rows and the budget.
        what: Label for the blocked construct (``"query"``, ``"search"``, ...), used in the
            message.

    Returns:
        str: A message describing the block, suitable for returning to the agent as tool
        output.
    """
    detail = str(exc).strip() or "(no detail provided)"
    # The block is corrective feedback for the agent, but also an observable event on the
    # operator side: logged alongside the reflected message.
    _logger.warning("%s blocked by the session row budget: %s", what, detail)
    return "\n".join(
        [
            f"Warning: the {what} result is NOT returned — the session row budget is exhausted.",
            f"Detail: {detail}",
            "Stop extracting rows: aggregate or summarize in the database to reduce volume, "
            "or start a new session to reset the budget.",
        ]
    )

format_estimate_block

format_estimate_block(exc: EstimateExceededError, *, what: str = 'query') -> str

Format an EXPLAIN row-estimate guardrail block as corrective feedback.

Turns the EstimateExceededError raised by GuardrailConfig.check_estimate into a message the agent can act on: the query was not executed because its estimated result set is too large, so the agent should refine its filters or aggregate and retry.

Parameters:

Name Type Description Default
exc EstimateExceededError

The guardrail exception raised when the estimate exceeded the threshold; its message already describes the estimate and the threshold.

required
what str

Label for the blocked construct ("query", "search", ...), used in the message.

'query'

Returns:

Name Type Description
str str

A message describing the block, suitable for returning to the agent as tool

str

output.

Source code in src/deep_db_agents/query_errors.py
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
def format_estimate_block(exc: EstimateExceededError, *, what: str = "query") -> str:
    """Format an EXPLAIN row-estimate guardrail block as corrective feedback.

    Turns the ``EstimateExceededError`` raised by ``GuardrailConfig.check_estimate`` into
    a message the agent can act on: the query was **not executed** because its estimated
    result set is too large, so the agent should refine its filters or aggregate and retry.

    Args:
        exc: The guardrail exception raised when the estimate exceeded the threshold; its
            message already describes the estimate and the threshold.
        what: Label for the blocked construct (``"query"``, ``"search"``, ...), used in
            the message.

    Returns:
        str: A message describing the block, suitable for returning to the agent as tool
        output.
    """
    detail = str(exc).strip() or "(no detail provided)"
    # The block is corrective feedback for the agent, but also an observable event on the
    # operator side: logged alongside the reflected message.
    _logger.warning("%s blocked by the estimate guardrail: %s", what, detail)
    return "\n".join(
        [
            f"Warning: the {what} was NOT executed by the database.",
            f"Detail: {detail}",
            f"Narrow the {what} with more selective filters or aggregate in the database "
            "to reduce the estimated result set, then retry.",
        ]
    )

format_query_error

format_query_error(exc: Exception, *, query: str | None = None, what: str = 'query') -> str

Format a driver exception as corrective feedback for the agent.

Parameters:

Name Type Description Default
exc Exception

The exception raised during execution (database driver error).

required
query str | None

The text of the submitted query/pipeline; included in the feedback if present, so the agent sees exactly what it got wrong.

None
what str

Label for the executed construct ("query", "pipeline", "Cypher query"), used in the message.

'query'

Returns:

Name Type Description
str str

A multi-line message describing the failure, suitable for returning to

str

the agent as tool output.

Source code in src/deep_db_agents/query_errors.py
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
def format_query_error(exc: Exception, *, query: str | None = None, what: str = "query") -> str:
    """Format a driver exception as corrective feedback for the agent.

    Args:
        exc: The exception raised during execution (database driver error).
        query: The text of the submitted query/pipeline; included in the feedback if
            present, so the agent sees exactly what it got wrong.
        what: Label for the executed construct (``"query"``, ``"pipeline"``,
            ``"Cypher query"``), used in the message.

    Returns:
        str: A multi-line message describing the failure, suitable for returning to
        the agent as tool output.
    """
    detail = _redact_secrets(str(exc).strip()) or "(no detail provided by the driver)"
    # The error becomes feedback for the agent, but it is also an observable event on
    # the operator side (failed or blocked query): logged with credentials already
    # redacted from the detail.
    _logger.warning("%s not executed: %s: %s", what, type(exc).__name__, detail)
    lines = [
        f"Error: the {what} was NOT executed by the database.",
        f"Error type: {type(exc).__name__}",
        f"Detail: {detail}",
    ]
    if query:
        text = query.strip()
        if len(text) > _MAX_QUERY_CHARS:
            text = text[:_MAX_QUERY_CHARS] + " …[truncated]"
        lines.append(f"{what.capitalize()} submitted:\n{text}")
    lines.append(
        f"The database rejected the request. Fix the {what} based on the error "
        "detail (syntax, table/column/field names, types or operators) and retry; "
        "if needed, inspect the schema first with the exploration tools."
    )
    return "\n".join(lines)