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

  1. Wrap the top level as an array: the file must start with [ and contain job objects
  2. Check you passed the right file to --completed-file
  3. Validate with a JSON parser (jq 'type') that the root is an array
  4. 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

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


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/8e7b35c5eb15e94d. Report an issue: GitHub.