{"record":{"id":"81e81b68c05fe077","repo":"paperclipai/paperclip","slug":"migrator-producer-lookup-failed-http-response-status","errorCode":null,"errorMessage":"Migrator producer lookup failed: HTTP ${response.status}","messagePattern":"Migrator producer lookup failed: HTTP (.+?)","errorType":"console","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/cloud-readiness.mjs","lineNumber":21,"sourceCode":"import { execFileSync } from \"node:child_process\";\nimport { mkdtempSync, rmSync, writeFileSync } from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { imageExists, versionFor } from \"./preview-artifacts.mjs\";\nimport { verifyPublished } from \"./cloud-migrator-artifacts.mjs\";\n\nconst repository = \"paperclipai/paperclip\";\nconst workflow = \".github/workflows/cloud-migrator-artifacts.yml\";\n\nexport async function migratorPublished(sha, fetchImpl, token) {\n  let pending = false;\n  const failures = [];\n  for (let page = 1; page <= 10; page++) {\n    const response = await fetchImpl(`https://api.github.com/repos/${repository}/actions/workflows/cloud-migrator-artifacts.yml/runs?branch=master&head_sha=${sha}&per_page=100&page=${page}`, {\n      headers: { Accept: \"application/vnd.github+json\", ...(token ? { Authorization: `Bearer ${token}` } : {}) },\n      redirect: \"error\", signal: AbortSignal.timeout(30_000),\n    });\n    if (!response.ok) throw new Error(`Migrator producer lookup failed: HTTP ${response.status}`);\n    const body = await response.json();\n    if (!Array.isArray(body.workflow_runs) || !Number.isSafeInteger(body.total_count) || body.total_count < 0 ||\n        (page === 1 && (body.total_count === 0) !== (body.workflow_runs.length === 0))) throw new Error(\"Invalid migrator producer response.\");\n    if (body.total_count === 0) return false;\n    for (const run of body.workflow_runs) {\n      if (run.head_sha !== sha || run.head_branch !== \"master\" || run.path !== workflow ||\n          run.head_repository?.id !== 1170821064 || run.head_repository.full_name !== repository ||\n          ![\"push\", \"workflow_dispatch\"].includes(run.event)) throw new Error(\"Migrator producer identity mismatch.\");\n      // Publication is immutable. A later failed manual run must not hide a\n      // successful exact-source publisher; the signed bundle is checked next.\n      if (run.status === \"completed\" && run.conclusion === \"success\") return true;\n      if (run.status !== \"completed\") pending = true;\n      else failures.push(`${run.id}: ${run.conclusion}`);\n    }\n    if (page * 100 >= body.total_count) {\n      if (pending) return false;\n      throw new Error(`Migrator producers failed: ${failures.join(\", \")}.`);\n    }","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/scripts/cloud-readiness.mjs#L3-L39","documentation":"migratorPublished() polls the GitHub Actions API for cloud-migrator-artifacts workflow runs on the given commit. When any page request returns a non-OK HTTP status it throws this error with the status code embedded. It is a fail-closed API transport check.","triggerScenarios":"The fetch to api.github.com/repos/paperclipai/paperclip/actions/workflows/cloud-migrator-artifacts.yml/runs returns 401/403/404/422/5xx — e.g. expired GH_TOKEN, rate-limited 403, renamed repository, or a GitHub outage.","commonSituations":"Expired or missing GitHub token in GH_TOKEN; hitting the unauthenticated 60 req/hr rate limit; GHE/proxy interference; GitHub API incident; transient network failure within the 30s AbortSignal timeout.","solutions":["Check GH_TOKEN validity and Actions read scope, then rerun; note the script retries at the waitForCloudArtifacts poll level, so transient statuses may self-heal on the next 20s poll.","If HTTP 403 with x-ratelimit-remaining: 0, wait for the rate-limit window to reset or use an authenticated token.","Verify api.github.com is reachable and the paperclipai/paperclip repository still exists at that name."],"exampleFix":"// before\nconst token = process.env.GH_TOKEN; // undefined or expired\n// after\nif (!process.env.GH_TOKEN) throw new Error(\"Set GH_TOKEN with Actions read scope before polling.\");\nconst token = process.env.GH_TOKEN;","handlingStrategy":"retry","validationCode":"// preflight\nconst probe = await fetch(\"https://api.github.com/rate_limit\", { headers: token ? { Authorization: `Bearer ${token}` } : {} });\nif (!probe.ok) throw new Error(`GitHub API unreachable/unauthorized: HTTP ${probe.status}`);","typeGuard":null,"tryCatchPattern":"try {\n  await waitForCloudArtifacts(sha);\n} catch (error) {\n  if (/Migrator producer lookup failed/.test(error.message)) {\n    console.error(\"GitHub API error — check GH_TOKEN scope and rate limits:\", error.message);\n    process.exitCode = 1;\n  } else throw error;\n}","preventionTips":["Always set GH_TOKEN with Actions read scope before running","Monitor rate limit via /rate_limit in long polls","Wrap the readiness check in the release script's own retry with backoff"],"tags":["github-api","http-error","network"],"backgroundTag":"http-error-response","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-22T01:17:13.364Z"}