{"record":{"id":"077eb161580514b2","repo":"paperclipai/paperclip","slug":"github-token-with-actions-read-access-is-required","errorCode":null,"errorMessage":"GITHUB_TOKEN with Actions read access is required.","messagePattern":"GITHUB_TOKEN with Actions read access is required\\.","errorType":"console","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/cloud-source-verification.mjs","lineNumber":156,"sourceCode":"export async function waitForSourceVerification(sha, {\n  api, now = Date.now, sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)),\n  timeoutMs = 45 * 60_000, intervalMs = 30_000, log = console.log,\n} = {}) {\n  assertSha(sha);\n  const deadline = now() + timeoutMs;\n  log(`Waiting for ${sourceVerificationJob} for ${sha}.`);\n  while (now() < deadline) {\n    const result = await readSourceVerification(sha, api);\n    if (result) return result;\n    const remaining = deadline - now();\n    if (remaining > 0) await sleep(Math.min(intervalMs, remaining));\n  }\n  throw new Error(`Cloud source verification timed out for ${sha}. Rerun Cloud readiness before retrying the release.`);\n}\n\nif (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {\n  try {\n    if (!process.env.GITHUB_TOKEN) throw new Error(\"GITHUB_TOKEN with Actions read access is required.\");\n    // One deadline for both layers: the reader stops retrying when the poll it\n    // serves is out of time, instead of extending the wait past its timeout.\n    const timeoutMs = 45 * 60_000;\n    const deadline = Date.now() + timeoutMs;\n    const api = createActionsReader({ token: process.env.GITHUB_TOKEN, deadlineAt: () => deadline });\n    const proof = await waitForSourceVerification(process.argv[2], { api, timeoutMs });\n    const message = `Source verification passed for ${proof.sha}: https://github.com/${repository}/actions/runs/${proof.runId}/attempts/${proof.attempt} (job ${proof.jobId}).`;\n    console.log(message);\n    if (process.env.GITHUB_STEP_SUMMARY) await appendFile(process.env.GITHUB_STEP_SUMMARY, `${message}\\n`);\n  } catch (error) {\n    console.error(error.message);\n    process.exitCode = 1;\n  }\n}\n","sourceCodeStart":138,"sourceCodeEnd":171,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/scripts/cloud-source-verification.mjs#L138-L171","documentation":"The CLI entry point of cloud-source-verification.mjs requires GITHUB_TOKEN in the environment because every GitHub Actions read needs a bearer token with Actions read access. When the env var is unset or empty, the script throws this immediately before any API call, and exits with code 1.","triggerScenarios":"Running `node scripts/cloud-source-verification.mjs <sha>` without GITHUB_TOKEN exported — fresh shell, CI job missing the env mapping, or a .env file that was never loaded (the script reads process.env only).","commonSituations":"Local run before sourcing credentials; GitHub Actions step that forgot `env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}`; token exported under a different name (GH_TOKEN, GITHUB_PAT); dotenv not loaded in a plain node script.","solutions":["Export the token before running: export GITHUB_TOKEN=$(gh auth token) or paste a PAT with Actions read.","In GitHub Actions, pass the secret: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} (or a PAT secret) on the step.","Check the variable name is exactly GITHUB_TOKEN, not GH_TOKEN or GITHUB_PAT: echo \"${GITHUB_TOKEN:+set}\".","Verify the token can read Actions: curl -sS -H \"Authorization: Bearer $GITHUB_TOKEN\" https://api.github.com/repos/paperclipai/paperclip/actions/workflows/cloud-readiness.yml"],"exampleFix":"// before\n$ node scripts/cloud-source-verification.mjs abc123...\nGITHUB_TOKEN with Actions read access is required.\n// after\n$ export GITHUB_TOKEN=$(gh auth token)\n$ node scripts/cloud-source-verification.mjs abc123...","handlingStrategy":"validation","validationCode":"if (!process.env.GITHUB_TOKEN) {\n  throw new Error('GITHUB_TOKEN must be set (PAT or GITHUB_TOKEN secret with Actions read)');\n}","typeGuard":"function hasGithubToken(env = process.env) {\n  return typeof env.GITHUB_TOKEN === 'string' && env.GITHUB_TOKEN.length > 0;\n}","tryCatchPattern":"try {\n  await runVerification(sha);\n} catch (e) {\n  if (e.message.includes('GITHUB_TOKEN')) {\n    console.error('Set GITHUB_TOKEN, e.g. export GITHUB_TOKEN=$(gh auth token)');\n    process.exitCode = 1;\n  }\n}","preventionTips":["Add a shell profile line: export GITHUB_TOKEN=$(gh auth token), or use a direnv/.env loader the script's environment actually reads.","In GitHub Actions, always map env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} on the step.","Do not rename the variable to GH_TOKEN/GITHUB_PAT — the script reads GITHUB_TOKEN only.","Preflight the token with a curl to the workflows endpoint before long polls."],"tags":["env-var","github-token","authentication","cli"],"backgroundTag":"missing-env-var","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}