{"record":{"id":"349390b535be1434","repo":"anuraghazra/github-readme-stats","slug":"no-tokens","errorCode":"NO_TOKENS","errorMessage":"No GitHub API tokens found","messagePattern":"No GitHub API tokens found","errorType":"error_code","errorClass":"CustomError","httpStatus":null,"severity":"critical","filePath":"src/common/retryer.js","lineNumber":29,"sourceCode":").length;\nconst RETRIES = process.env.NODE_ENV === \"test\" ? 7 : PATs;\n\n/**\n * @typedef {import(\"axios\").AxiosResponse} AxiosResponse Axios response.\n * @typedef {(variables: any, token: string, retriesForTests?: number) => Promise<AxiosResponse>} FetcherFunction Fetcher function.\n */\n\n/**\n * Try to execute the fetcher function until it succeeds or the max number of retries is reached.\n *\n * @param {FetcherFunction} fetcher The fetcher function.\n * @param {any} variables Object with arguments to pass to the fetcher function.\n * @param {number} retries How many times to retry.\n * @returns {Promise<any>} The response from the fetcher function.\n */\nconst retryer = async (fetcher, variables, retries = 0) => {\n  if (!RETRIES) {\n    throw new CustomError(\"No GitHub API tokens found\", CustomError.NO_TOKENS);\n  }\n\n  if (retries > RETRIES) {\n    throw new CustomError(\n      \"Downtime due to GitHub API rate limiting\",\n      CustomError.MAX_RETRY,\n    );\n  }\n\n  try {\n    // try to fetch with the first token since RETRIES is 0 index i'm adding +1\n    let response = await fetcher(\n      variables,\n      // @ts-ignore\n      process.env[`PAT_${retries + 1}`],\n      // used in tests for faking rate limit\n      retries,\n    );","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/anuraghazra/github-readme-stats/blob/54a7985aeefda00d5eadb55b80c17c7f976c37d2/src/common/retryer.js#L11-L47","documentation":"Thrown by the retryer on its very first line when RETRIES is 0. RETRIES is computed once at module load as the count of environment variables matching /PAT_\\d*$/ (or hardcoded to 7 when NODE_ENV === 'test'). With zero PAT_N variables there is no token to authenticate any GitHub API call, so the retryer refuses to run. The secondary message directs the user to add a PAT_1 env var.","triggerScenarios":"Any request to any endpoint (stats, pin, gist, top-langs, wakatime) when the deployed environment defines no PAT_1, PAT_2, ... variables. Concretely: Object.keys(process.env).filter(key => /PAT_\\d*$/.exec(key)).length === 0 and NODE_ENV !== 'test'.","commonSituations":"A fresh Vercel/local clone where the PAT_1 environment variable was never set; the variable was renamed (e.g. set as GITHUB_TOKEN instead of PAT_1); the variable is scoped to a different Vercel environment (e.g. set only in 'Preview' but hit on 'Production'); or a .env file is present but dotenv wasn't loaded before this module initialized.","solutions":["Create a fine-grained or classic GitHub personal access token with public_repo (and read:user) scopes.","Set PAT_1 in the deployment environment (Vercel Project Settings > Environment Variables, or `export PAT_1=...` locally / in .env).","Verify with `printenv | grep '^PAT_'` that the variable is actually visible to the Node process, and that NODE_ENV is not 'test' in production (which would mask a missing-token misconfiguration).","For higher traffic, add PAT_2, PAT_3, ... to increase the retry budget."],"exampleFix":"// before: no token env vars set\n\n// after (Vercel CLI)\n// vercel env add PAT_1\n// or locally:\n// echo \"PAT_1=ghp_xxxxxxxxxxxxxxxxxxxx\" >> .env","handlingStrategy":"validation","validationCode":"// Fail fast at boot if no tokens are configured.\nfunction assertTokensConfigured() {\n  const count = Object.keys(process.env).filter((k) => /PAT_\\d*$/.test(k)).length;\n  if (count === 0 && process.env.NODE_ENV !== \"test\") {\n    throw new Error(\n      \"No PAT_N env vars set. Add PAT_1 with a GitHub token before starting the server.\",\n    );\n  }\n}\n// call during module init / before listen()","typeGuard":null,"tryCatchPattern":"// In a server bootstrap, surface a clear startup error instead of failing per-request.\ntry {\n  assertTokensConfigured();\n} catch (e) {\n  console.error(e.message);\n  process.exit(1);\n}","preventionTips":["Set PAT_1 in every Vercel environment (Production, Preview, Development) you intend to serve from.","Add a CI step that asserts /PAT_\\d+$/ appears in the deployed env for non-test builds.","Remember NODE_ENV === 'test' force-sets RETRIES=7, so tests pass without tokens — don't use green tests as proof of config."],"tags":["authentication","environment","deployment","github-api","tokens"],"backgroundTag":null,"analyzedSha":"54a7985aeefda00d5eadb55b80c17c7f976c37d2","analyzedAt":"2026-08-12T23:20:41.776Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}