{"record":{"id":"7b54a6291a3027bd","repo":"anuraghazra/github-readme-stats","slug":"err","errorCode":null,"errorMessage":"${err}","messagePattern":"\\$\\{err\\}","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/fetchers/stats.js","lineNumber":202,"sourceCode":" *\n * @param {string} username GitHub username.\n * @returns {Promise<number>} Total commits.\n *\n * @description Done like this because the GitHub API does not provide a way to fetch all the commits. See\n * #92#issuecomment-661026467 and #211 for more information.\n */\nconst totalCommitsFetcher = async (username) => {\n  if (!githubUsernameRegex.test(username)) {\n    logger.log(\"Invalid username provided.\");\n    throw new Error(\"Invalid username provided.\");\n  }\n\n  let res;\n  try {\n    res = await retryer(fetchTotalCommits, { login: username });\n  } catch (err) {\n    logger.log(err);\n    throw new Error(err);\n  }\n\n  const totalCount = res.data.total_count;\n  if (!totalCount || isNaN(totalCount)) {\n    throw new CustomError(\n      \"Could not fetch total commits.\",\n      CustomError.GITHUB_REST_API_ERROR,\n    );\n  }\n  return totalCount;\n};\n\n/**\n * Fetch stats for a given username.\n *\n * @param {string} username GitHub username.\n * @param {boolean} include_all_commits Include all commits.\n * @param {string[]} exclude_repo Repositories to exclude.","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/anuraghazra/github-readme-stats/blob/54a7985aeefda00d5eadb55b80c17c7f976c37d2/src/fetchers/stats.js#L184-L220","documentation":"Generic Error thrown in totalCommitsFetcher's catch block wrapping whatever the retryer threw: `throw new Error(err)`. Because the retryer can throw CustomError(NO_TOKENS) or CustomError(MAX_RETRY) (and network errors), wrapping them in a fresh Error stringifies the original and discards its .type and .secondaryMessage — a known code smell that loses structured error metadata downstream. The visible message is the stringified underlying error.","triggerScenarios":"include_all_commits=true and the retryer (driving fetchTotalCommits against the REST /search/commits endpoint) throws: all tokens rate-limited (MAX_RETRY), no tokens configured (NO_TOKENS), or a network/axios failure that the retryer re-throws when e.response is absent.","commonSituations":"Self-hosted instance with no/insufficient tokens hitting the all-commits path; a rate-limit storm against the REST search endpoint; or a network blip between the instance and api.github.com. The original error type is invisible because of the wrap.","solutions":["Ensure PAT_1 (and more) are set — NO_TOKENS surfaces here as a stringified CustomError.","Add tokens to raise the MAX_RETRY ceiling for the REST endpoint.","If transient, retry the request after the rate-limit window resets.","If you don't need all-time commits, drop include_all_commits=true to avoid the REST path entirely."],"exampleFix":"// before (config)\n// include_all_commits=true with no PAT tokens -> 'Error: No GitHub API tokens found'\n\n// after\n// export PAT_1=ghp_xxx  (and optionally drop include_all_commits)","handlingStrategy":"try-catch","validationCode":"// The wrapped error is opaque; pre-validate token presence to avoid NO_TOKENS reaching here.\nfunction assertTokensForRestPath() {\n  const has = Object.keys(process.env).some((k) => /PAT_\\d*$/.test(k));\n  if (!has && process.env.NODE_ENV !== \"test\") {\n    throw new Error(\"include_all_commits requires at least one PAT_N token\");\n  }\n}","typeGuard":null,"tryCatchPattern":"// The original CustomError type is lost in the wrap; match on substrings as a workaround.\ntry {\n  stats.totalCommits = await totalCommitsFetcher(username);\n} catch (err) {\n  if (/No GitHub API tokens found/.test(err.message)) handleMissingTokens();\n  else if (/rate limiting/.test(err.message)) handleRateLimit();\n  else throw err;\n}","preventionTips":["Note this error wraps and stringifies the underlying CustomError, losing .type — match on message text if you must branch.","Set PAT tokens and limit include_all_commits usage to reduce exposure to the REST search path."],"tags":["stats","error-wrapping","retry","rest-api","include-all-commits"],"backgroundTag":null,"analyzedSha":"54a7985aeefda00d5eadb55b80c17c7f976c37d2","analyzedAt":"2026-08-12T23:20:41.776Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}