cube-js/cube · error · UserError
Invalid Job query format: ${error.message || error.toString(
Error message
Invalid Job query format: ${error.message || error.toString()} What it means
This UserError is thrown by the pre-aggregations jobs endpoint (`POST /cubejs-system/v1/pre aggregations/jobs`) when the request body fails Joi validation against `preAggsJobsRequestSchema`. The body must contain a valid `action` ('post' or 'get') and, depending on the action, a valid `selector` (for 'post') or `tokens` (for 'get'). The Joi `error.message` is interpolated into the message so you can see exactly which field was invalid.
Source
Thrown at packages/cubejs-api-gateway/src/gateway.ts:1067
* }
* ```
*/
private async preAggregationsJobs(req: Request, res: ExpressResponse) {
const response = this.resToResultFn(res);
const requestStarted = new Date();
const context = <RequestContext>req.context;
const query = <PreAggsJobsRequest>req.body;
let result;
try {
await this.assertApiScope('jobs', req?.context?.securityContext);
if (!query || Object.keys(query).length === 0) {
throw new UserError('No job description provided');
}
const { error, value } = preAggsJobsRequestSchema.validate(query);
if (error) {
throw new UserError(`Invalid Job query format: ${error.message || error.toString()}`);
}
switch (query.action) {
case 'post':
result = await this.preAggregationsJobsPOST(
context,
<PreAggsSelector>value.selector
);
if (result.length === 0) {
throw new UserError(
'A user\'s selector doesn\'t match any of the ' +
'pre-aggregations defined in the data model.'
);
}
break;
case 'get':
result = await this.preAggregationsJobsGET(
context,View on GitHub (pinned to 7d981676b3)
Solutions
- Read the Joi message appended after 'Invalid Job query format:' — it names the exact offending field and expected type.
- For build jobs, send `{"action": "post", "selector": {"contexts": [...], "dataSources": [...], "cubes": [...], "preAggregations": [...], "timezones": [...]}}`.
- For status polling, send `{"action": "get", "tokens": ["<jobToken>", ...]}` (optionally `"resType": "object"`).
- Ensure `action` is exactly lowercase 'post' or 'get' and that the body is a JSON object, not a string or array.
- Compare your payload against the schema version in your installed cubejs-api-gateway package, as fields have changed between releases.
Example fix
// before
curl -X POST /cubejs-system/v1/pre-aggregations/jobs -d '{"action":"rebuild","selector":{"cubes":["Events"]}}'
// after
curl -X POST /cubejs-system/v1/pre-aggregations/jobs -d '{"action":"post","selector":{"contexts":[{"dataSources":["default"]}],"cubes":["Events"],"timezones":["UTC"]}}' Defensive patterns
Strategy: validation
Validate before calling
function validateJobsPayload(body) {
if (!body || typeof body !== 'object') return 'body must be a JSON object';
if (body.action !== 'post' && body.action !== 'get') return 'action must be "post" or "get"';
if (body.action === 'post') {
const s = body.selector;
if (!s || typeof s !== 'object') return 'post requires a selector object';
if (s.dateRange && (!Array.isArray(s.dateRange) || s.dateRange.length !== 2)) return 'dateRange must be [start, end]';
}
if (body.action === 'get' && (!Array.isArray(body.tokens) || body.tokens.some(t => typeof t !== 'string'))) {
return 'get requires tokens: string[]';
}
return null;
} Type guard
function isValidJobsRequest(q: unknown): q is { action: 'post' | 'get'; selector?: Record<string, unknown>; tokens?: string[] } {
return !!q && typeof q === 'object' &&
['post', 'get'].includes((q as any).action);
} Try / catch
try {
const res = await fetch('/cubejs-system/v1/pre-aggregations/jobs', { method: 'POST', body: JSON.stringify(payload) });
const data = await res.json();
if (res.status !== 200) throw new Error(data.error || 'jobs request failed');
} catch (e) {
if (String(e.message).includes('Invalid Job query format')) {
console.error('Payload failed schema validation:', e.message); // fix the named field
}
} Prevention
- Keep the jobs payload generation in one typed helper (TypeScript interface for the request).
- Mirror the Joi schema rules from cubejs-api-gateway in your client-side validation.
- Pin and review the Cube version when upgrading, since the request schema can change.
- Test the payload with curl against a dev instance before wiring it into automation.
When it happens
Trigger: POSTing to the pre-aggregations jobs API with a body that passes the empty-check but fails schema validation: missing/unknown `action` value, `action: 'post'` without a well-formed `selector` object (contexts, dataSources, cubes, preAggregations, timezones, dateRange of wrong types), or `action: 'get'` with missing/`tokens` not an array of strings, or unexpected extra fields disallowed by the schema.
Common situations: Hand-crafted curl/HTTP payloads for the pre-aggregations jobs API; automation scripts calling the jobs endpoint after a schema change or Cube version upgrade (the request schema has tightened over versions); typos like `action: 'Post'` or `selectors` instead of `selector`; passing the whole selector as a JSON string instead of an object.
Related errors
- The '${query.action}' action type doesn't supported.
- Cannot parse selector date range ${selector.dateRange}
- Can't parse date: '${from}'
- Can't parse date: '${to}'
- Can't parse date: '${dateString}'
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/062d51845f9590e0.
Report an issue: GitHub.