{"record":{"id":"bee3d2e92961e6e3","repo":"midudev/autoskills","slug":"raw-fetch-failed-res-status-url","errorCode":null,"errorMessage":"raw fetch failed: ${res.status} ${url}","messagePattern":"raw fetch failed: (.+?) (.+?)","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/autoskills/scripts/sync-skills.mjs","lineNumber":279,"sourceCode":"  }\n\n  candidates.sort((a, b) => a.length - b.length);\n  return candidates;\n}\n\nasync function downloadRawFile(repo, sha, repoPath, destFile) {\n  const url = `https://raw.githubusercontent.com/${repo}/${sha}/${repoPath}`;\n  const headers = { \"User-Agent\": \"autoskills-sync\" };\n  if (GITHUB_TOKEN) headers.Authorization = `Bearer ${GITHUB_TOKEN}`;\n  const ac = new AbortController();\n  const timer = setTimeout(() => ac.abort(), TARBALL_TIMEOUT_MS);\n  try {\n    const res = await fetch(url, {\n      headers,\n      signal: ac.signal,\n    });\n    if (!res.ok || !res.body) {\n      throw new Error(`raw fetch failed: ${res.status} ${url}`);\n    }\n    mkdirSync(dirname(destFile), { recursive: true });\n    await pipeline(res.body, createWriteStream(destFile));\n  } finally {\n    clearTimeout(timer);\n  }\n}\n\nasync function materializeSkillsFromTree(repo, sha, skillNames, destRoot) {\n  const tree = await fetchRepoTree(repo, sha);\n  const found = new Map(); // skillName → relative dir within destRoot\n  for (const skillName of skillNames) {\n    const dirs = findSkillDirsInTree(tree, skillName);\n    if (dirs.length === 0) continue;\n    const pick = dirs[0];\n    const blobs = tree.filter(\n      (t) =>\n        t.type === \"blob\" &&","sourceCodeStart":261,"sourceCodeEnd":297,"githubUrl":"https://github.com/midudev/autoskills/blob/0ec725320d2137253ab2e68e7ba8a072148e741a/packages/autoskills/scripts/sync-skills.mjs#L261-L297","documentation":"downloadRawFile fetches an individual file from raw.githubusercontent.com and streams it to disk. A non-ok response or missing body throws this error with the HTTP status and URL — most often 404 for a path that doesn't exist at that ref, or 403 rate limiting.","triggerScenarios":"fetch(rawUrl) yields res.ok === false or res.body === null while downloading a single raw file — wrong path/branch in the tree, deleted file, or rate-limited unauthenticated raw access.","commonSituations":"A SKILL.md listed in the git tree was deleted between tree fetch and file download (race); case-sensitivity mismatch in the file path; unauthenticated raw request rate limit exceeded.","solutions":["Verify the exact URL opens in a browser — fix the path/ref if 404","Set GITHUB_TOKEN and ensure it is sent for raw requests to lift rate limits","Re-run the sync to recover from transient GitHub 5xx/timeout","Check file name case matches the repo exactly (Linux raw serving is case-sensitive)"],"exampleFix":"// before\nawait downloadRawFile(\"https://raw.githubusercontent.com/org/repo/main/Skill.md\", dest);\n// after\nawait downloadRawFile(\"https://raw.githubusercontent.com/org/repo/main/SKILL.md\", dest);","handlingStrategy":"retry","validationCode":"// confirm the raw URL exists before streaming to disk\nconst probe = await fetch(url, { method: \"HEAD\" });\nif (probe.status === 404) throw new Error(`raw file missing: ${url}`);","typeGuard":null,"tryCatchPattern":"try {\n  await downloadRawFile(url, dest);\n} catch (err) {\n  const m = err.message.match(/^raw fetch failed: (\\d{3})/);\n  if (m) {\n    if (m[1] === \"404\") throw new Error(`Permanent: file gone — ${url}`);\n    if (m[1] === \"403\" || m[1].startsWith(\"5\")) await retryWithBackoff(() => downloadRawFile(url, dest));\n  } else throw err;\n}","preventionTips":["Send GITHUB_TOKEN on raw requests to avoid 403 rate limits","Match file paths and case exactly as they exist in the repo","Treat 404 as permanent and re-sync the tree before retrying","Add retries with backoff for 403/5xx statuses"],"tags":["http","network","github","raw"],"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"}