{"record":{"id":"13b95ac71f502019","repo":"cube-js/cube","slug":"no-job-description-provided","errorCode":null,"errorMessage":"No job description provided","messagePattern":"No job description provided","errorType":"validation","errorClass":"UserError","httpStatus":null,"severity":"error","filePath":"packages/cubejs-api-gateway/src/gateway.ts","lineNumber":1062,"sourceCode":"   *     \"ec1232ea3356f04f8be313fecf3deb4d\",\n   *     \"48b75d5c466fa579c936dc451f498f69\",\n   *     \"76509837091396dc204abb1016c48e75\",\n   *     \"52264769f81f6ff62062a93d6f6fbdb2\"\n   *   ]\n   * }\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            );","sourceCodeStart":1044,"sourceCodeEnd":1080,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/packages/cubejs-api-gateway/src/gateway.ts#L1044-L1080","documentation":"The pre-aggregations jobs endpoint (/cubejs-system/v1/pre_aggregations/jobs) requires a non-empty JSON body describing the job (e.g. action, preAggregations list). If req.body is missing or an empty object, ApiGateway throws this UserError before even running schema validation, because there is no job description to act on.","triggerScenarios":"POSTing to the pre-aggs jobs endpoint with no body, body: {}, or a body that serializes to {} (e.g. Content-Type not application/json so the body parser yields an empty object), instead of e.g. { action: 'post', preAggregations: [...] }.","commonSituations":"Forgetting to send a JSON body in fetch/axios calls; missing Content-Type: application/json header so the body parses empty; empty POST health-check pings hitting the jobs endpoint; copy-pasted requests that dropped the payload.","solutions":["Send a JSON body matching preAggsJobsRequestSchema, e.g. { action: 'post', preAggregations: [{ tableName: 'orders_main' }] }","Set the Content-Type: application/json header so the body parser populates req.body","Check for typos: an incorrectly keyed payload may deserialize to an object the schema later rejects — the 'No job description provided' case is specifically empty/missing body","Verify with curl -v or network tab that a non-empty body is actually transmitted"],"exampleFix":"// before\nawait fetch(`${apiUrl}/cubejs-system/v1/pre_aggregations/jobs`, { method: 'POST', headers: { authorization: token } });\n// after\nawait fetch(`${apiUrl}/cubejs-system/v1/pre_aggregations/jobs`, { method: 'POST', headers: { authorization: token, 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'post', preAggregations: [{ tableName: 'orders_main' }] }) });","handlingStrategy":"validation","validationCode":"function assertJobsBody(body) {\n  if (!body || Object.keys(body).length === 0) throw new Error('pre_aggregations/jobs requires a non-empty JSON body, e.g. { action: \"post\", preAggregations: [...] }');\n}","typeGuard":"const hasJobDescription = (b) => typeof b === 'object' && b !== null && Object.keys(b).length > 0;","tryCatchPattern":"try {\n  const res = await fetch(`${apiUrl}/cubejs-system/v1/pre_aggregations/jobs`, { method: 'POST', headers: jsonHeaders, body: JSON.stringify(jobsRequest) });\n  const data = await res.json();\n  if (data.error === 'No job description provided') throw new Error('Jobs endpoint got an empty body — check payload serialization');\n  return data;\n} catch (e) {\n  console.error('Pre-aggs jobs call failed:', e.message);\n  throw e;\n}","preventionTips":["Always send a non-empty JSON body with action and preAggregations fields","Set Content-Type: application/json — without it req.body may parse to {}","Verify the payload with JSON.stringify before the call (empty objects serialize to '{}')","Don't fire-and-forget empty POSTs (e.g. health checks) at this endpoint"],"tags":["request-validation","rest-api","pre-aggregations","http-400"],"backgroundTag":"request-body-validation-failed","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}