windmill-labs/windmill · error · Error
Completed jobs file must contain an array of jobs
Error message
Completed jobs file must contain an array of jobs
What it means
'wmill jobs push' reads the completed-jobs JSON file (default completed_jobs.json) to import via the API. The CLI requires it to be a JSON array of job objects and throws this error when the parsed top-level value is anything else.
Source
Thrown at cli/src/commands/jobs/jobs.ts:198
"Import cancelled. Please scale down workers and try again."
);
log.info("You can skip this check with --skip-worker-check flag.");
return;
}
}
} catch (e) {
log.debug(`Could not check for active workers: ${e}`);
}
}
// Push completed jobs
const completedPath = opts.completedFile || "completed_jobs.json";
try {
const completedContent = await readTextFile(completedPath);
const completedJobs = JSON.parse(completedContent);
if (!Array.isArray(completedJobs)) {
throw new Error("Completed jobs file must contain an array of jobs");
}
const completedResult = await wmill.importCompletedJobs({
workspace: ws.workspaceId,
requestBody: completedJobs,
});
log.info(colors.green(`Completed jobs: ${completedResult}`));
} catch (e: any) {
if (e.code === "ENOENT") {
log.info(
colors.yellow(
`No completed jobs file found at ${completedPath}, skipping`
)
);
} else {
throw new Error(`Failed to push completed jobs: ${e}`);
}View on GitHub (pinned to e474e8803c)
Solutions
- Wrap the top level as an array: the file must start with [ and contain job objects
- Check you passed the right file to --completed-file
- Validate with a JSON parser (jq 'type') that the root is an array
- Re-export from the source ensuring a bare array of completed-job objects
Example fix
// before (completed_jobs.json)
{"jobs": [{"path": "f/foo", ...}]}
// after
[{"path": "f/foo", ...}] Defensive patterns
Strategy: validation
Validate before calling
import { readTextFile } from "node:fs/promises"; // or Deno
const jobs = JSON.parse(await readTextFile(completedPath));
if (!Array.isArray(jobs)) {
throw new Error(`${completedPath} must be a JSON array of job objects`);
} Type guard
function isJobArray(v: unknown): v is Record<string, unknown>[] {
return Array.isArray(v) && v.every((j) => j !== null && typeof j === "object");
} Try / catch
try {
await wmillJobsPush({ completedFile: path });
} catch (e) {
if (String(e).includes("must contain an array of jobs")) {
console.error(`Fix ${path}: top-level must be [ ... ], not an object`);
}
} Prevention
- Export completed jobs as a bare JSON array, not wrapped in an object
- Validate the file with 'jq type' (expect 'array') before pushing
- Don't confuse completed_jobs.json with queued_jobs.json paths
- Add a CI lint step validating the schema of these files
When it happens
Trigger: The completed jobs file contains a JSON object (e.g. {"jobs": [...]}) instead of a bare array, is a JSON-export wrapped in other structure, or the wrong file was pointed at via --completed-file.
Common situations: Exporting from another tool that wraps arrays in an object; hand-written file missing brackets; mixing up queued/completed file paths; truncated file parsed as something unexpected.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Failed to push completed jobs: ${e}
- Queued jobs file must contain an array of jobs
- Invalid migration name '${name}': use only letters, digits,
- Unknown workspace dependencies file format: ${path}. Valid f
- Cannot push flow ${remotePath}: step(s) reference non-worksp
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/8e7b35c5eb15e94d.
Report an issue: GitHub.