{"record":{"id":"d5e36cf3b597487c","repo":"anuraghazra/github-readme-stats","slug":"res-statustext-d5e36c","errorCode":"res.statusText","errorMessage":"${res.data.errors[0].message}","messagePattern":"\\$\\{res\\.data\\.errors\\[0\\]\\.message\\}","errorType":"error_code","errorClass":"CustomError","httpStatus":null,"severity":"error","filePath":"src/fetchers/top-languages.js","lineNumber":83,"sourceCode":"  size_weight = 1,\n  count_weight = 0,\n) => {\n  if (!username) {\n    throw new MissingParamError([\"username\"]);\n  }\n\n  const res = await retryer(fetcher, { login: username });\n\n  if (res.data.errors) {\n    logger.error(res.data.errors);\n    if (res.data.errors[0].type === \"NOT_FOUND\") {\n      throw new CustomError(\n        res.data.errors[0].message || \"Could not fetch user.\",\n        CustomError.USER_NOT_FOUND,\n      );\n    }\n    if (res.data.errors[0].message) {\n      throw new CustomError(\n        wrapTextMultiline(res.data.errors[0].message, 90, 1)[0],\n        res.statusText,\n      );\n    }\n    throw new CustomError(\n      \"Something went wrong while trying to retrieve the language data using the GraphQL API.\",\n      CustomError.GRAPHQL_ERROR,\n    );\n  }\n\n  let repoNodes = res.data.data.user.repositories.nodes;\n  /** @type {Record<string, boolean>} */\n  let repoToHide = {};\n  const allExcludedRepos = [...exclude_repo, ...excludeRepositories];\n\n  // populate repoToHide map for quick lookup\n  // while filtering out\n  if (allExcludedRepos) {","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/anuraghazra/github-readme-stats/blob/54a7985aeefda00d5eadb55b80c17c7f976c37d2/src/fetchers/top-languages.js#L65-L101","documentation":"The non-NOT_FOUND, message-bearing GraphQL error branch. It fires when res.data.errors[0].message is truthy but the error's type is not \"NOT_FOUND\". Critically, the error code passed to CustomError is res.statusText, not a stable constant: for a GraphQL response delivered over HTTP 200 that string is literally \"OK\", and for an HTTP error response surfaced by the retryer (which returns e.response) it is the HTTP phrase such as \"Forbidden\". Because res.statusText is almost never a key in SECONDARY_ERROR_MESSAGES, the secondaryMessage degrades to the statusText itself, so callers cannot reliably switch on the code.","triggerScenarios":"GitHub's GraphQL endpoint returns HTTP 200 with a body-level errors array carrying a message but a type other than NOT_FOUND (and other than RATE_LIMITED, which the retryer already retries). Examples: GitHub service instability returning \"Something went wrong while executing your query.\", secondary-rate-limit messages whose type is not RATE_LIMITED, or schema/field errors after an API change. Less commonly, the retryer returns a non-2xx e.response and the body still parses into res.data.errors with a message.","commonSituations":"A live GitHub API incident (check githubstatus.com); a PAT whose scopes trigger a GraphQL-level error with a message; an upstream schema change that breaks the hardcoded query in src/fetchers/top-languages.js:20; transient partial failures during high traffic.","solutions":["Check https://www.githubstatus.com for an active GitHub API incident and retry after it resolves.","Inspect the server logs: logger.error(res.data.errors) prints the raw GraphQL error just before this throw; read its message to find the real cause.","Verify the PAT_1 token used by the retryer has the expected scopes and is not revoked.","Retry with exponential backoff; if the message indicates a permanent schema problem, update the GraphQL query string in the fetcher to match the current GitHub schema."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// You cannot validate an upstream GraphQL error away, but you can cap concurrency\n// and ensure a valid token is configured to reduce transient failures.\nfunction assertTokenConfigured() {\n  if (!process.env.PAT_1) {\n    throw new Error(\"PAT_1 env var is not set; GitHub GraphQL will reject requests\");\n  }\n}\nassertTokenConfigured();","typeGuard":"// This error's `type` is res.statusText (e.g. \"OK\"/\"Forbidden\"), so guard by message shape\nfunction isUpstreamGraphqlError(err) {\n  return err instanceof CustomError && typeof err.message === \"string\";\n}","tryCatchPattern":"async function fetchWithRetry(username, attempts = 3) {\n  for (let i = 0; i < attempts; i++) {\n    try {\n      return await fetchTopLanguages(username);\n    } catch (err) {\n      const transient = err instanceof CustomError &&\n        ![CustomError.USER_NOT_FOUND, CustomError.NO_TOKENS].includes(err.type);\n      if (!transient || i === attempts - 1) throw err;\n      await new Promise((r) => setTimeout(r, 2 ** i * 500)); // backoff\n    }\n  }\n}","preventionTips":["Surface the raw message logged by logger.error(res.data.errors) to diagnose the true upstream cause.","Keep PAT tokens valid and sufficiently scoped to avoid GraphQL-level auth errors with messages.","Treat this branch as transient and retry with backoff; escalate only if it persists across attempts."],"tags":["github-api","graphql","upstream","status","fragile-code"],"backgroundTag":null,"analyzedSha":"54a7985aeefda00d5eadb55b80c17c7f976c37d2","analyzedAt":"2026-08-12T23:20:41.776Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}