paperclipai/paperclip · error · Error

Cloud readiness job listing is incomplete.

Error message

Cloud readiness job listing is incomplete.

What it means

The script pages jobs up to 10 pages of 100. If page 10 comes back with a full 100 jobs, it cannot know the listing ended and throws this error instead of silently truncating. It also fires when a full page arrives on page 10 after the push. Effectively: the run attempt has more than 1000 jobs, which the script refuses to read incompletely.

Solutions

  1. Check the run's real job count; a Cloud readiness attempt should never approach 1000 jobs — investigate what generated so many (matrix explosion or repeated reruns).
  2. If it is a stub/test, make later pages return fewer than 100 jobs so pagination terminates.
  3. Raise the page cap (for page <= 10) in scripts/cloud-source-verification.mjs if the workflow legitimately grows beyond 1000 jobs.
  4. Reduce the workflow's job fan-out so the matrix fits within the pagination cap.

Example fix

// before
for (let page = 1; page <= 10; page += 1) {
// after
for (let page = 1; page <= 20; page += 1) {
Defensive patterns

Strategy: validation

Validate before calling

// check job count of the attempt before running the poller
const first = await api(`/repos/${repo}/actions/runs/${runId}/attempts/${attempt}/jobs?per_page=100&page=1`);
if (first.total_count >= 1000) console.warn('attempt exceeds the script pagination cap');

Type guard

function fitsPaginationCap(jobCount, cap = 1000) {
  return Number.isSafeInteger(jobCount) && jobCount < cap;
}

Try / catch

try {
  const proof = await readSourceVerification(sha, api);
} catch (e) {
  if (e.message.includes('job listing is incomplete')) {
    console.error('Attempt has >1000 jobs; shrink the workflow matrix or raise the page cap.');
  }
}

Prevention

When it happens

Trigger: GET .../runs/{id}/attempts/{n}/jobs?page=10&per_page=100 returns exactly 100 jobs, meaning more pages may exist and the true job list would be truncated.

Common situations: A pathological workflow matrix with thousands of jobs on one run attempt; a stubbed api() that keeps returning full pages regardless of page number.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18). Data as JSON: /api/errors/723c8ce9d126bf1f. Report an issue: GitHub.

Appendix: source

Thrown at scripts/cloud-source-verification.mjs:45

  }
  const listing = await api(`/repos/${repository}/actions/workflows/${workflow.id}/runs?head_sha=${sha}&event=push&branch=master&per_page=100`);
  if (!Array.isArray(listing.workflow_runs) || !Number.isSafeInteger(listing.total_count) ||
      listing.total_count < 0 || listing.total_count > 100 || listing.workflow_runs.length !== listing.total_count) {
    throw new Error("Cloud readiness run listing is incomplete.");
  }
  const run = listing.workflow_runs.filter((candidate) => trustedRun(candidate, sha, workflow.id))
    .sort((a, b) => b.id - a.id)[0];
  if (!run) return undefined;

  // Attempt-specific jobs prevent an earlier successful attempt from blessing
  // a later rerun. Keep pagination even though today's matrix fits one page.
  const jobs = [];
  for (let page = 1; page <= 10; page += 1) {
    const batch = await api(`/repos/${repository}/actions/runs/${run.id}/attempts/${run.run_attempt}/jobs?per_page=100&page=${page}`);
    if (!Array.isArray(batch.jobs)) throw new Error("Cloud readiness job listing is malformed.");
    jobs.push(...batch.jobs);
    if (batch.jobs.length < 100) break;
    if (page === 10) throw new Error("Cloud readiness job listing is incomplete.");
  }
  const matches = jobs.filter((job) => job.name === sourceVerificationJob);
  if (matches.length > 1) throw new Error("Cloud source verification job is ambiguous.");
  const job = matches[0];
  if (job?.status === "completed" && job.conclusion === "success" &&
      job.head_sha === sha && job.run_id === run.id && job.run_attempt === run.run_attempt) {
    // Re-read the run after its jobs: a rerun that started during polling must
    // not let the previous attempt through. Changes are retried next poll.
    const current = await api(`/repos/${repository}/actions/runs/${run.id}`);
    if (!trustedRun(current, sha, workflow.id) || current.run_attempt !== run.run_attempt) return undefined;
    return { sha, runId: run.id, attempt: run.run_attempt, jobId: job.id };
  }
  if (job?.status === "completed" || run.status === "completed") {
    throw new Error(`Cloud source verification did not pass for ${sha} (run ${run.id}, attempt ${run.run_attempt}). Rerun Cloud readiness before retrying the release.`);
  }
  return undefined;
}

View on GitHub (pinned to 3f1d897a7c)