Judgment Labs Logo
PythonJQL

Responses and errors

Python JQL public response envelopes, nullability, and error handling.

judgeval JQL source on GitHub

Query response

type JqlQueryResponse = {
  query_id: string;
  rows: Array<Record<string, unknown>> | null;
  row_count: number | null;
  elapsed_ms: number;
};
FieldMeaning
query_idServer-generated query identifier for diagnostics
rowsResult rows; keys and values depend on the select, pipeline, or discovery kind
row_countNumber of returned rows when supplied by the executor
elapsed_msServer-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.

Statuserror valueMeaningCaller action
400BAD_QUERY (code)Structurally valid request that JQL cannot compile or runFix the field, grain, operation, or constraint using message and hint
400BAD_PRESENTATION (code)Presentation references invalid/duplicate/missing output fieldsMatch field keys to produced query columns
400Validation failed, Parse error, Postgres error (prose)Envelope-level failure, such as an out-of-range limitFix the request envelope, not the query
422Code, or Validation failed (prose)Request or IR schema validation failedFix types, required fields, extra fields, or exclusive options
401Authentication failed (prose)Missing or invalid credentialsCheck the API key and X-Organization-Id
403Forbidden (prose)Organization authorization failedCheck organization access and role
404Resource not found (prose)Project is missing or outside the organization, or public JQL is not enabled for the organizationCorrect the client project; if it is right, ask for the feature to be enabled
429QUERY_RATE_LIMITED (code)Public JQL rate limitHonor Retry-After, which is always set on 429
502JQL_UPSTREAM_UNAVAILABLE (code)Query service unavailableRetry later; do not rewrite the query to bypass the service
503Service unavailable (prose)Dependency unavailable, including degraded rate-limit infrastructureRetry later
500Internal server error, Unknown error (prose)Unhandled failureRetry; 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.