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

  1. Delete destDir/cached tarball and re-download from GitHub so the archive has the standard root directory
  2. Verify the tarball with `tar -tzf <file> | head` — it should show one top-level folder
  3. Ensure the tarball comes from GitHub's codeload endpoint, not a custom archive format
  4. 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

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)