{"record":{"id":"062d51845f9590e0","repo":"cube-js/cube","slug":"invalid-job-query-format-error-message-error","errorCode":null,"errorMessage":"Invalid Job query format: ${error.message || error.toString()}","messagePattern":"Invalid Job query format: (.+?)","errorType":"validation","errorClass":"UserError","httpStatus":null,"severity":"error","filePath":"packages/cubejs-api-gateway/src/gateway.ts","lineNumber":1067,"sourceCode":"   * }\n   * ```\n   */\n  private async preAggregationsJobs(req: Request, res: ExpressResponse) {\n    const response = this.resToResultFn(res);\n    const requestStarted = new Date();\n    const context = <RequestContext>req.context;\n    const query = <PreAggsJobsRequest>req.body;\n    let result;\n    try {\n      await this.assertApiScope('jobs', req?.context?.securityContext);\n\n      if (!query || Object.keys(query).length === 0) {\n        throw new UserError('No job description provided');\n      }\n\n      const { error, value } = preAggsJobsRequestSchema.validate(query);\n      if (error) {\n        throw new UserError(`Invalid Job query format: ${error.message || error.toString()}`);\n      }\n\n      switch (query.action) {\n        case 'post':\n          result = await this.preAggregationsJobsPOST(\n            context,\n            <PreAggsSelector>value.selector\n          );\n          if (result.length === 0) {\n            throw new UserError(\n              'A user\\'s selector doesn\\'t match any of the ' +\n              'pre-aggregations defined in the data model.'\n            );\n          }\n          break;\n        case 'get':\n          result = await this.preAggregationsJobsGET(\n            context,","sourceCodeStart":1049,"sourceCodeEnd":1085,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/packages/cubejs-api-gateway/src/gateway.ts#L1049-L1085","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ncurl -X POST /cubejs-system/v1/pre-aggregations/jobs -d '{\"action\":\"rebuild\",\"selector\":{\"cubes\":[\"Events\"]}}'\n\n// after\ncurl -X POST /cubejs-system/v1/pre-aggregations/jobs -d '{\"action\":\"post\",\"selector\":{\"contexts\":[{\"dataSources\":[\"default\"]}],\"cubes\":[\"Events\"],\"timezones\":[\"UTC\"]}}'","handlingStrategy":"validation","validationCode":"function validateJobsPayload(body) {\n  if (!body || typeof body !== 'object') return 'body must be a JSON object';\n  if (body.action !== 'post' && body.action !== 'get') return 'action must be \"post\" or \"get\"';\n  if (body.action === 'post') {\n    const s = body.selector;\n    if (!s || typeof s !== 'object') return 'post requires a selector object';\n    if (s.dateRange && (!Array.isArray(s.dateRange) || s.dateRange.length !== 2)) return 'dateRange must be [start, end]';\n  }\n  if (body.action === 'get' && (!Array.isArray(body.tokens) || body.tokens.some(t => typeof t !== 'string'))) {\n    return 'get requires tokens: string[]';\n  }\n  return null;\n}","typeGuard":"function isValidJobsRequest(q: unknown): q is { action: 'post' | 'get'; selector?: Record<string, unknown>; tokens?: string[] } {\n  return !!q && typeof q === 'object' &&\n    ['post', 'get'].includes((q as any).action);\n}","tryCatchPattern":"try {\n  const res = await fetch('/cubejs-system/v1/pre-aggregations/jobs', { method: 'POST', body: JSON.stringify(payload) });\n  const data = await res.json();\n  if (res.status !== 200) throw new Error(data.error || 'jobs request failed');\n} catch (e) {\n  if (String(e.message).includes('Invalid Job query format')) {\n    console.error('Payload failed schema validation:', e.message); // fix the named field\n  }\n}","preventionTips":["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."],"tags":["validation","rest-api","pre-aggregations","request-format"],"backgroundTag":"request-schema-validation-failed","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}