anuraghazra/github-readme-stats · error · Error

${err}

Error message

${err}

What it means

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.

Source

Thrown at src/fetchers/stats.js:202

 *
 * @param {string} username GitHub username.
 * @returns {Promise<number>} Total commits.
 *
 * @description Done like this because the GitHub API does not provide a way to fetch all the commits. See
 * #92#issuecomment-661026467 and #211 for more information.
 */
const totalCommitsFetcher = async (username) => {
  if (!githubUsernameRegex.test(username)) {
    logger.log("Invalid username provided.");
    throw new Error("Invalid username provided.");
  }

  let res;
  try {
    res = await retryer(fetchTotalCommits, { login: username });
  } catch (err) {
    logger.log(err);
    throw new Error(err);
  }

  const totalCount = res.data.total_count;
  if (!totalCount || isNaN(totalCount)) {
    throw new CustomError(
      "Could not fetch total commits.",
      CustomError.GITHUB_REST_API_ERROR,
    );
  }
  return totalCount;
};

/**
 * Fetch stats for a given username.
 *
 * @param {string} username GitHub username.
 * @param {boolean} include_all_commits Include all commits.
 * @param {string[]} exclude_repo Repositories to exclude.

View on GitHub (pinned to 54a7985aee)

Solutions

  1. Ensure PAT_1 (and more) are set — NO_TOKENS surfaces here as a stringified CustomError.
  2. Add tokens to raise the MAX_RETRY ceiling for the REST endpoint.
  3. If transient, retry the request after the rate-limit window resets.
  4. If you don't need all-time commits, drop include_all_commits=true to avoid the REST path entirely.

Example fix

// before (config)
// include_all_commits=true with no PAT tokens -> 'Error: No GitHub API tokens found'

// after
// export PAT_1=ghp_xxx  (and optionally drop include_all_commits)
Defensive patterns

Strategy: try-catch

Validate before calling

// The wrapped error is opaque; pre-validate token presence to avoid NO_TOKENS reaching here.
function assertTokensForRestPath() {
  const has = Object.keys(process.env).some((k) => /PAT_\d*$/.test(k));
  if (!has && process.env.NODE_ENV !== "test") {
    throw new Error("include_all_commits requires at least one PAT_N token");
  }
}

Try / catch

// The original CustomError type is lost in the wrap; match on substrings as a workaround.
try {
  stats.totalCommits = await totalCommitsFetcher(username);
} catch (err) {
  if (/No GitHub API tokens found/.test(err.message)) handleMissingTokens();
  else if (/rate limiting/.test(err.message)) handleRateLimit();
  else throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of anuraghazra/github-readme-stats@54a7985aee (2026-08-12). Data as JSON: /api/errors/7b54a6291a3027bd. Report an issue: GitHub.