{"record":{"id":"f944aa4ae494d756","repo":"decolua/9router","slug":"failed-to-fetch-github-usage-error-message","errorCode":null,"errorMessage":"Failed to fetch GitHub usage: ${error.message}","messagePattern":"Failed to fetch GitHub usage: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"open-sse/services/usage/github.js","lineNumber":87,"sourceCode":"          chat: {\n            used: usedQuotas.chat || 0,\n            total: monthlyQuotas.chat || 0,\n            unlimited: false,\n            resetAt,\n          },\n          completions: {\n            used: usedQuotas.completions || 0,\n            total: monthlyQuotas.completions || 0,\n            unlimited: false,\n            resetAt,\n          },\n        },\n      };\n    }\n\n    return { message: \"GitHub Copilot connected. Unable to parse quota data.\" };\n  } catch (error) {\n    throw new Error(`Failed to fetch GitHub usage: ${error.message}`);\n  }\n}\n\nfunction formatGitHubQuotaSnapshot(quota) {\n  if (!quota) return { used: 0, total: 0, unlimited: true };\n\n  return {\n    used: quota.entitlement - quota.remaining,\n    total: quota.entitlement,\n    remaining: quota.remaining,\n    unlimited: quota.unlimited || false,\n  };\n}\n","sourceCodeStart":69,"sourceCodeEnd":101,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/open-sse/services/usage/github.js#L69-L101","documentation":"This is the outer catch-all of getGitHubUsage: any error thrown inside the function (including errors 111 and 112) is re-thrown prefixed with 'Failed to fetch GitHub usage:'. The original message is preserved via error.message, so the root cause (missing token, HTTP error, JSON parse failure) is chained in the text.","triggerScenarios":"Any failure path inside getGitHubUsage: falsy accessToken, non-OK upstream response, response.json() failing on a non-JSON body, or an unexpected runtime error while parsing quota_snapshots / quota_reset_date fields.","commonSituations":"Callers seeing this wrapper in logs/usage handlers; double wrapping when the usage handler itself adds another prefix; the inner cause being an expired token or upstream 4xx.","solutions":["Strip the prefix and inspect error.message to find the root cause (missing token vs API error)","If the cause is a missing/invalid token, re-run the GitHub OAuth authorization flow","Guard the call in try/catch and render a 'reconnect GitHub' prompt instead of crashing the usage panel","Ensure the upstream body is JSON — HTML error pages will fail at response.json()"],"exampleFix":"// before\nconst usage = await getGitHubUsage(token, data, proxy);\n// after\nlet usage;\ntry {\n  usage = await getGitHubUsage(token, data, proxy);\n} catch (e) {\n  usage = { error: true, message: e.message, reconnectNeeded: /access token/i.test(e.message) };\n}","handlingStrategy":"try-catch","validationCode":"if (!account?.accessToken) return { reconnect: true, quotas: null };","typeGuard":null,"tryCatchPattern":"try {\n  usage = await getGitHubUsage(token, data, proxy);\n} catch (e) {\n  // e.message is the prefixed chain: inspect inner cause\n  const cause = e.message.replace(/^Failed to fetch GitHub usage: /, \"\");\n  return { error: cause, reconnectNeeded: /access token|API error: 40/.test(cause) };\n}","preventionTips":["Catch this wrapper at the usage-handler boundary and degrade gracefully","Parse the inner message to distinguish auth vs network causes","Never let a usage fetch crash the main routing path","Cache last-known usage so the UI survives transient failures"],"tags":["github-copilot","usage","error-wrapping"],"backgroundTag":"usage-fetch-failed","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}