Responses and errors
TypeScript JQL public response envelopes, nullability, and error handling.
judgeval-js JQL source on GitHub
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.
Response objects are plain JSON. The generated types are structural,
so narrow rows before use rather than asserting a row shape.
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 (unknown),
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.
TypeScript exception handling
import { JudgevalAPIError } from "judgeval";
try {
const result = await client.query(query);
} catch (error) {
if (error instanceof JudgevalAPIError) {
console.error(error.status, error.code, error.message, error.hint);
}
}JudgevalAPIError exposes status, code, message, hint, and optional retryAfterSeconds, which is populated from the Retry-After header.
Failures raised before the request
Malformed .agg(...), .trend(...), and .pipe(...) calls throw a
TypeError from the builder before any request is sent, so they never surface
as a 400.