midudev/autoskills · error · Error
Tarball fetch failed
Error message
Tarball fetch failed: ${res.status} ${url} What it means
downloadTarball fetches a GitHub codeload tarball URL over HTTP and streams it to a file. If the response is not ok (non-2xx) or has no body, it throws this error including the HTTP status and URL. Common statuses: 404 (repo/branch/tag gone), 403 (rate limit), 5xx (GitHub server error).
Solutions
- Re-run after checking the URL in a browser — if 404, the ref/repo no longer exists
- Set a valid GITHUB_TOKEN to raise the API/codeload rate limit; if 403, wait for the rate-limit reset
- Check https://www.githubstatus.com for GitHub outages on 5xx
- If status is from an abort (timeout), raise TARBALL_TIMEOUT_MS for large repos
Example fix
// before // no token -> 403 rate limited await downloadTarball(url, dest); // after process.env.GITHUB_TOKEN = "ghp_..."; // authenticated requests await downloadTarball(url, dest);
Defensive patterns
Strategy: retry
Validate before calling
// pre-check the tarball URL responds 200
const probe = await fetch(url, { method: "HEAD", headers: GITHUB_TOKEN ? { Authorization: `Bearer ${GITHUB_TOKEN}` } : {} });
if (!probe.ok) throw new Error(`tarball URL not fetchable: ${probe.status} ${url}`); Try / catch
async function downloadWithRetry(url, dest, attempts = 3) {
for (let i = 0; i < attempts; i++) {
try { return await downloadTarball(url, dest); }
catch (err) {
if (!err.message.startsWith("Tarball fetch failed")) throw err;
const status = parseInt(err.message.match(/(\d{3})/)?.[1] ?? "0", 10);
if (status === 404) throw err; // permanent
await new Promise(r => setTimeout(r, 2 ** i * 1000));
}
}
throw new Error(`tarball download failed after ${attempts} attempts`);
} Prevention
- Set GITHUB_TOKEN to avoid unauthenticated rate limits (403)
- Verify the branch/tag still exists before syncing
- Handle 404 as permanent and 403/5xx as retryable
- Monitor https://www.githubstatus.com during CI runs
When it happens
Trigger: fetch(url) returns res.ok === false or res.body === null while downloading a repo tarball — 404 for missing ref, 403 rate-limited without/with an exhausted GITHUB_TOKEN, 5xx from GitHub.
Common situations: Hitting GitHub's unauthenticated rate limit during bulk syncs; syncing a repo branch/tag that was deleted; transient GitHub 5xx; GITHUB_TOKEN expired or revoked.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- GitHub for
- raw fetch failed
- GitHub rate limit exceeded
- download failed for
- ⚠️ No se pudo crear la release en GitHub (¿tienes gh…
AI-assisted analysis of midudev/autoskills@0ec725320d (2026-09-15).
Data as JSON: /api/errors/998da52f7d67b6b3.
Report an issue: GitHub.
Appendix: source
Thrown at packages/autoskills/scripts/sync-skills.mjs:220
sizeKB: body.size || 0,
};
}
// Tarball download size threshold (KB). Above this we use per-file fetch.
const HEAVY_REPO_KB = 50_000;
// Hard timeout for tarball downloads. Some repos have slow codeload CDNs.
const TARBALL_TIMEOUT_MS = 180_000;
async function downloadTarball(repo, sha, destFile) {
const url = `https://codeload.github.com/${repo}/tar.gz/${sha}`;
const headers = { "User-Agent": "autoskills-sync" };
if (GITHUB_TOKEN) headers.Authorization = `Bearer ${GITHUB_TOKEN}`;
const ac = new AbortController();
const timer = setTimeout(() => ac.abort(), TARBALL_TIMEOUT_MS);
try {
const res = await fetch(url, { headers, signal: ac.signal });
if (!res.ok || !res.body) {
throw new Error(`Tarball fetch failed: ${res.status} ${url}`);
}
await pipeline(res.body, createWriteStream(destFile));
} finally {
clearTimeout(timer);
}
}
async function fetchRepoTree(repo, sha) {
const res = await ghFetch(`https://api.github.com/repos/${repo}/git/trees/${sha}?recursive=1`);
const body = await res.json();
if (body.truncated) {
throw new Error(`git tree truncated for ${repo}@${sha.slice(0, 7)}`);
}
return body.tree || [];
}
function findSkillDirsInTree(tree, skillName) {
// Returns array of { dir } where dir/SKILL.md exists in the tree.View on GitHub (pinned to 0ec725320d)