{"record":{"id":"3dd9b633f9c8e646","repo":"midudev/autoskills","slug":"github-res-status-res-statustext-for-url","errorCode":null,"errorMessage":"GitHub ${res.status} ${res.statusText} for ${url}","messagePattern":"GitHub (.+?) (.+?) for (.+?)","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/autoskills/scripts/sync-skills.mjs","lineNumber":161,"sourceCode":"// ── GitHub helpers ───────────────────────────────────────────\n\nasync function ghFetch(url) {\n  const headers = {\n    \"User-Agent\": \"autoskills-sync\",\n    Accept: \"application/vnd.github+json\",\n    \"X-GitHub-Api-Version\": \"2022-11-28\",\n  };\n  if (GITHUB_TOKEN) headers.Authorization = `Bearer ${GITHUB_TOKEN}`;\n  const res = await fetch(url, { headers });\n  if (!res.ok) {\n    const resetAt = Number(res.headers.get(\"x-ratelimit-reset\") || 0) * 1000;\n    const resetSuffix = resetAt ? ` (resets ${new Date(resetAt).toISOString()})` : \"\";\n    if (res.status === 403 && res.headers.get(\"x-ratelimit-remaining\") === \"0\") {\n      throw new Error(\n        `GitHub 403 rate limit exceeded${resetSuffix} for ${url}. Set GITHUB_TOKEN or GH_TOKEN to increase the limit.`,\n      );\n    }\n    throw new Error(`GitHub ${res.status} ${res.statusText} for ${url}`);\n  }\n  return res;\n}\n\nfunction resolveRepoHead(repo) {\n  const result = spawnSync(\n    \"git\",\n    [\"ls-remote\", \"--symref\", `https://github.com/${repo}.git`, \"HEAD\"],\n    {\n      encoding: \"utf-8\",\n      stdio: [\"ignore\", \"pipe\", \"pipe\"],\n    },\n  );\n  if (result.status !== 0) {\n    throw new Error(`git ls-remote failed for ${repo}: ${result.stderr.trim() || \"unknown error\"}`);\n  }\n\n  let defaultBranch = \"main\";","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/midudev/autoskills/blob/0ec725320d2137253ab2e68e7ba8a072148e741a/packages/autoskills/scripts/sync-skills.mjs#L143-L179","documentation":"ghFetch throws this generic error for any GitHub response that is not ok and is not the specific rate-limit case. The message embeds the HTTP status, status text, and the requested URL so the developer can see which GitHub endpoint failed and why (404 for missing repo/path, 401/403 for auth problems, 5xx for GitHub incidents).","triggerScenarios":"ghFetch receives a non-ok response other than 403-with-zero-remaining — e.g. requesting a repo tree or file that doesn't exist (404), an invalid token (401), or GitHub server errors (500/502).","commonSituations":"Typo in a repo name, branch, or skill path in the sync configuration; renamed/moved upstream repository; an expired PAT returning 401; transient GitHub incidents returning 5xx.","solutions":["Read the status and URL in the message: 404 means fix the repo/branch/path; 401 means fix the token; 5xx means retry later.","Verify the repository, ref (from resolveRepoHead), and file paths in your sync config actually exist on GitHub.","Check/regenerate GITHUB_TOKEN if the status is 401 or 403.","For 5xx, wait and re-run the sync; check the GitHub status page for incidents."],"exampleFix":"// before (config)\nconst repo = \"org/old-skill-repo\";   // renamed -> 404\n// GitHub 404 Not Found for https://api.github.com/repos/org/old-skill-repo/...\n\n// after\nconst repo = \"org/new-skill-repo\";","handlingStrategy":"try-catch","validationCode":"async function assertGithubUrlReachable(url, headers = {}) {\n  const res = await fetch(url, { method: \"HEAD\", headers });\n  if (!res.ok) throw new Error(`GitHub endpoint check failed: ${res.status} ${res.statusText} for ${url}`);\n}\n// validate repo/branch/path config before running the sync loop","typeGuard":null,"tryCatchPattern":"try {\n  const res = await ghFetch(url);\n} catch (e) {\n  if (/GitHub \\d{3}/.test(e.message) && !e.message.includes(\"rate limit\")) {\n    const status = Number(e.message.match(/GitHub (\\d{3})/)?.[1]);\n    if (status === 404) throw new Error(`Config error: repo/ref/path not found -> ${e.message}`);\n    if (status >= 500) return ghFetch(url); // transient: retry once\n    throw e;\n  } else throw e;\n}","preventionTips":["Validate repo names, refs, and file paths in sync config against the GitHub API before bulk fetching.","Handle 404 separately from 5xx: fix config vs. retry later.","Log the offending URL (already in the message) with each sync run for quick diagnosis.","Watch the GitHub status page and add retry/backoff around transient 5xx responses."],"tags":["github","http","api","network"],"backgroundTag":"http-error-response","analyzedSha":"0ec725320d2137253ab2e68e7ba8a072148e741a","analyzedAt":"2026-09-15T14:12:31.090Z","contentChangedAt":"2026-09-15T14:12:31.090Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}