{"record":{"id":"ecc210bec1e79720","repo":"windmill-labs/windmill","slug":"queued-jobs-file-must-contain-an-array-of-jobs","errorCode":null,"errorMessage":"Queued jobs file must contain an array of jobs","messagePattern":"Queued jobs file must contain an array of jobs","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"cli/src/commands/jobs/jobs.ts","lineNumber":226,"sourceCode":"    if (e.code === \"ENOENT\") {\n      log.info(\n        colors.yellow(\n          `No completed jobs file found at ${completedPath}, skipping`\n        )\n      );\n    } else {\n      throw new Error(`Failed to push completed jobs: ${e}`);\n    }\n  }\n\n  // Push queued jobs\n  const queuedPath = opts.queuedFile || \"queued_jobs.json\";\n  try {\n    const queuedContent = await readTextFile(queuedPath);\n    const queuedJobs = JSON.parse(queuedContent);\n\n    if (!Array.isArray(queuedJobs)) {\n      throw new Error(\"Queued jobs file must contain an array of jobs\");\n    }\n\n    const queuedResult = await wmill.importQueuedJobs({\n      workspace: ws.workspaceId,\n      requestBody: queuedJobs,\n    });\n\n    log.info(colors.green(`Queued jobs: ${queuedResult}`));\n  } catch (e: any) {\n    if (e.code === \"ENOENT\") {\n      log.info(\n        colors.yellow(`No queued jobs file found at ${queuedPath}, skipping`)\n      );\n    } else {\n      throw new Error(`Failed to push queued jobs: ${e}`);\n    }\n  }\n}","sourceCodeStart":208,"sourceCodeEnd":244,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/cli/src/commands/jobs/jobs.ts#L208-L244","documentation":"Thrown by `wmill job push` (pushJobs) in the Windmill CLI when the queued-jobs file (default queued_jobs.json, overridable with --queued-file) parses as valid JSON but is not a JSON array. The CLI forwards the parsed value directly as the `requestBody` of `wmill.importQueuedJobs`, whose API contract requires a list of queued-job objects, so a non-array body is rejected before any network call.","triggerScenarios":"Running `wmill job push` with a queued-jobs file whose top-level JSON value is an object ({...}), a string, a number, or null instead of an array of job objects.","commonSituations":"The file was hand-edited and the array wrapper was lost; a single job object was exported instead of an array; the file was written by another tool that emits {\"jobs\": [...]} wrapper objects; a JSONL file (multiple objects, no enclosing array) was pointed at --queued-file.","solutions":["Open the file and ensure the top-level value is a JSON array: wrap the object(s) in [ ... ].","If the file wraps jobs in an object like {\"jobs\": [...]}, extract the inner array into the file.","If converting from JSONL, merge the newline-delimited objects into a single comma-separated array.","Re-export the queued jobs with the matching `wmill job pull` command so the file has the canonical array shape."],"exampleFix":"// before (queued_jobs.json)\n{\"path\": \"f/my_script\", \"args\": {}}\n\n// after\n[{\"path\": \"f/my_script\", \"args\": {}}]","handlingStrategy":"validation","validationCode":"const jobs = JSON.parse(await readTextFile(queuedPath));\nif (!Array.isArray(jobs)) throw new Error(`${queuedPath} must be a JSON array of jobs`);","typeGuard":"function isJobArray(v: unknown): v is Record<string, unknown>[] {\n  return Array.isArray(v) && v.every((x) => typeof x === \"object\" && x !== null);\n}","tryCatchPattern":"try {\n  await wmill.importQueuedJobs({ workspace: ws, requestBody: queuedJobs });\n} catch (e) {\n  if (String(e).includes(\"must contain an array\")) {\n    console.error(`Fix ${queuedPath}: top level must be [...]`);\n  }\n  throw e;\n}","preventionTips":["Always generate queued_jobs.json via `wmill job pull`, never hand-edit the top level.","Validate the file with `jq 'type == \"array\"' queued_jobs.json` before pushing.","Never point --queued-file at a JSONL or wrapper-object export."],"tags":["cli","validation","json"],"backgroundTag":"invalid-json-structure","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}