midudev/autoskills · error · Error
Empty tarball in
Error message
Empty tarball in ${destDir} What it means
After extracting, extractTarball reads destDir expecting GitHub tarball layout: exactly one top-level directory (repo-owner-sha/) containing the content. If no directory entry is found, it throws this error. It guards against empty or unexpectedly-shaped archives before the rest of the sync proceeds.
Solutions
- Delete destDir/cached tarball and re-download from GitHub so the archive has the standard root directory
- Verify the tarball with `tar -tzf <file> | head` — it should show one top-level folder
- Ensure the tarball comes from GitHub's codeload endpoint, not a custom archive format
- Check disk space; a full disk can yield a partial extract with no directories
Example fix
// before
// hand-built tarball with files at root
// after
// use the GitHub codeload tarball URL
const url = `https://codeload.github.com/${repo}/tar.gz/refs/heads/${branch}`; Defensive patterns
Strategy: validation
Validate before calling
// inspect archive shape before extraction
const listing = execSync(`tar -tzf ${tarFile}`, { encoding: "utf8" });
const roots = new Set(listing.split("\n").filter(Boolean).map(l => l.split("/")[0]));
if (roots.size !== 1) throw new Error(`unexpected archive layout: ${[...roots]}`); Try / catch
try {
await syncSkills(opts);
} catch (err) {
if (err.message.startsWith("Empty tarball")) {
console.error("Archive had no content directory; re-download from GitHub codeload");
// delete destDir + cached tarball, retry once
} else throw err;
} Prevention
- Only use GitHub codeload tarballs, which always have a single root dir
- Verify archives with `tar -tzf | head` showing one top-level folder
- Remove stale empty destDirs before retrying extraction
- Guard the pipeline so failed downloads never 'succeed' with 0-byte files
When it happens
Trigger: readdirSync(destDir) contains no entry that statSync reports as a directory — the tarball extracted nothing, only files at the root, or the extraction target is empty.
Common situations: A zero-byte or corrupt tarball that tar 'successfully' extracted nothing from; a hand-crafted or non-GitHub archive without the single root folder convention; leftover empty destDir from a failed prior run.
Understand the failure class
Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.
Related errors
AI-assisted analysis of midudev/autoskills@0ec725320d (2026-09-15).
Data as JSON: /api/errors/3ebd0607fbb7205d.
Report an issue: GitHub.
Appendix: source
Thrown at packages/autoskills/scripts/sync-skills.mjs:323
if (shouldSkipSkillFile(rel)) continue;
const dest = join(destRoot, skillName, rel);
await downloadRawFile(repo, sha, blob.path, dest);
}
found.set(skillName, join(destRoot, skillName));
}
return found;
}
function extractTarball(tarFile, destDir) {
const r = spawnSync("tar", ["-xzf", tarFile, "-C", destDir], {
stdio: FLAGS.verbose ? "inherit" : "pipe",
});
if (r.status !== 0) {
throw new Error(`tar extract failed (status ${r.status})`);
}
const entries = readdirSync(destDir);
const root = entries.find((e) => statSync(join(destDir, e)).isDirectory());
if (!root) throw new Error(`Empty tarball in ${destDir}`);
return join(destDir, root);
}
function runGit(args, label) {
const result = spawnSync("git", args, {
encoding: "utf-8",
stdio: ["ignore", "pipe", "pipe"],
});
if (result.status !== 0) {
throw new Error(`${label} failed: ${result.stderr.trim() || "unknown error"}`);
}
return result.stdout;
}
function materializeSkillsFromSparseClone(repo, branch, skillNames, destRoot) {
const repoDir = join(destRoot, "repo");
runGit(
[View on GitHub (pinned to 0ec725320d)