Responses and errors
Python JQL public response envelopes, nullability, and error handling.
Query response
type JqlQueryResponse = {
query_id: string;
rows: Array<Record<string, unknown>> | null;
row_count: number | null;
elapsed_ms: number;
};| Field | Meaning |
|---|---|
query_id | Server-generated query identifier for diagnostics |
rows | Result rows; keys and values depend on the select, pipeline, or discovery kind |
row_count | Number of returned rows when supplied by the executor |
elapsed_ms | Server-side elapsed time in milliseconds |
rows and row_count are nullable by contract. Do not infer row schemas from
row_count; branch on the query operation and inspect returned keys.
Responses are TypedDict values, so read them with key access
(result["rows"]), not attribute access. Import the types from
judgeval.jql when you need to annotate your own helpers.
Presentation response
type JqlPresentationResponse = {
query_id: string;
presentation: ChartPresentation | TablePresentation;
frame: {
schema: Array<{
key: string;
data_type: "string" | "number" | "duration" | "datetime";
nullable: boolean;
}>;
rows: Array<Record<string, unknown>>;
} | null;
elapsed_ms: number;
};The public API declares presentation and frame as unknown-typed passthroughs,
and the generated SDK types mirror that (Any),
but the server returns the concrete shape above. SQL is deliberately removed at
the public API boundary.
Error envelope
{
"error": "BAD_QUERY",
"message": "query.select.agg.q: q is required for quantile and only quantile",
"hint": "send a structured JQL query object"
}Public endpoints document error statuses 400, 401, 403, 404, 422,
429, 502, and 503. A 500 is also possible for unhandled failures and is
not part of the declared contract.
error is not uniformly a machine code. Query-level failures return a
stable snake_case code; authentication, authorization, routing, and availability
failures return a human-readable sentence instead. Branch on the HTTP status
first, and only treat error as a code for the statuses marked below.
| Status | error value | Meaning | Caller action |
|---|---|---|---|
400 | BAD_QUERY (code) | Structurally valid request that JQL cannot compile or run | Fix the field, grain, operation, or constraint using message and hint |
400 | BAD_PRESENTATION (code) | Presentation references invalid/duplicate/missing output fields | Match field keys to produced query columns |
400 | Validation failed, Parse error, Postgres error (prose) | Envelope-level failure, such as an out-of-range limit | Fix the request envelope, not the query |
422 | Code, or Validation failed (prose) | Request or IR schema validation failed | Fix types, required fields, extra fields, or exclusive options |
401 | Authentication failed (prose) | Missing or invalid credentials | Check the API key and X-Organization-Id |
403 | Forbidden (prose) | Organization authorization failed | Check organization access and role |
404 | Resource not found (prose) | Project is missing or outside the organization, or public JQL is not enabled for the organization | Correct the client project; if it is right, ask for the feature to be enabled |
429 | QUERY_RATE_LIMITED (code) | Public JQL rate limit | Honor Retry-After, which is always set on 429 |
502 | JQL_UPSTREAM_UNAVAILABLE (code) | Query service unavailable | Retry later; do not rewrite the query to bypass the service |
503 | Service unavailable (prose) | Dependency unavailable, including degraded rate-limit infrastructure | Retry later |
500 | Internal server error, Unknown error (prose) | Unhandled failure | Retry; report if persistent |
Compiler codes are passed through verbatim in the error field on 400 and
422. Common ones include UNKNOWN_COLUMN, FIELD_NOT_ON_GRAIN,
RATE_NEEDS_FILTER, RESULT_TOO_LARGE, SCAN_TOO_LARGE, QUERY_TIMEOUT,
GROUPING_TOO_LARGE, QUERY_MEMORY_LIMIT, BAD_FIELD, BAD_STATUS,
BAD_TIME, BAD_AGG, and BAD_REQUEST, along with grain guards such as
AGG_GRAIN, RANKED_GRAIN, PIPE_GRAIN, and SPAN_REL_GRAIN.
Python exception handling
from judgeval.exceptions import JudgmentAPIError
try:
result = client.query(query)
except JudgmentAPIError as error:
print(error.status_code, error.code, error, error.hint)The Python SDK maps validation responses to JudgmentValidationError, conflicts to JudgmentConflictError, and other failures to JudgmentAPIError.
Failures raised before the request
JudgmentProjectNotFoundError subclasses ValueError, not
JudgmentAPIError, and is raised before any request is sent when the client's
project name does not resolve. Catch it separately.