paperclipai/paperclip · error · Error
GITHUB_TOKEN with Actions read access is required.
Error message
GITHUB_TOKEN with Actions read access is required.
What it means
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.
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
Example fix
// before $ node scripts/cloud-source-verification.mjs abc123... GITHUB_TOKEN with Actions read access is required. // after $ export GITHUB_TOKEN=$(gh auth token) $ node scripts/cloud-source-verification.mjs abc123...
Defensive patterns
Strategy: validation
Validate before calling
if (!process.env.GITHUB_TOKEN) {
throw new Error('GITHUB_TOKEN must be set (PAT or GITHUB_TOKEN secret with Actions read)');
} Type guard
function hasGithubToken(env = process.env) {
return typeof env.GITHUB_TOKEN === 'string' && env.GITHUB_TOKEN.length > 0;
} Try / catch
try {
await runVerification(sha);
} catch (e) {
if (e.message.includes('GITHUB_TOKEN')) {
console.error('Set GITHUB_TOKEN, e.g. export GITHUB_TOKEN=$(gh auth token)');
process.exitCode = 1;
}
} Prevention
- 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.
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- ANTHROPIC_API_KEY is required in the CLI process environment
- --api-key-env must name a valid environment variable.
- CreateOS requires an API key in the environment config or…
- No credential found. Set
- A safe, unique --revision is required
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/077eb161580514b2.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/cloud-source-verification.mjs:156
export async function waitForSourceVerification(sha, {
api, now = Date.now, sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
timeoutMs = 45 * 60_000, intervalMs = 30_000, log = console.log,
} = {}) {
assertSha(sha);
const deadline = now() + timeoutMs;
log(`Waiting for ${sourceVerificationJob} for ${sha}.`);
while (now() < deadline) {
const result = await readSourceVerification(sha, api);
if (result) return result;
const remaining = deadline - now();
if (remaining > 0) await sleep(Math.min(intervalMs, remaining));
}
throw new Error(`Cloud source verification timed out for ${sha}. Rerun Cloud readiness before retrying the release.`);
}
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
try {
if (!process.env.GITHUB_TOKEN) throw new Error("GITHUB_TOKEN with Actions read access is required.");
// One deadline for both layers: the reader stops retrying when the poll it
// serves is out of time, instead of extending the wait past its timeout.
const timeoutMs = 45 * 60_000;
const deadline = Date.now() + timeoutMs;
const api = createActionsReader({ token: process.env.GITHUB_TOKEN, deadlineAt: () => deadline });
const proof = await waitForSourceVerification(process.argv[2], { api, timeoutMs });
const message = `Source verification passed for ${proof.sha}: https://github.com/${repository}/actions/runs/${proof.runId}/attempts/${proof.attempt} (job ${proof.jobId}).`;
console.log(message);
if (process.env.GITHUB_STEP_SUMMARY) await appendFile(process.env.GITHUB_STEP_SUMMARY, `${message}\n`);
} catch (error) {
console.error(error.message);
process.exitCode = 1;
}
}
View on GitHub (pinned to 3f1d897a7c)