headroomlabs-ai/headroom · error · Error

tar failed for ${tarballPath}: ${result.stderr || result.std

Error message

tar failed for ${tarballPath}: ${result.stderr || result.stdout || "unknown error"}

What it means

verify_npm_release_assets.mjs extracts `package/dist/package.json` from each release tarball by spawning `tar -xzf`. A nonzero exit status (or a null status when the `tar` binary cannot be spawned at all) throws with the captured stderr/stdout, or 'unknown error' when neither stream has content. This usually indicates a corrupt tarball or a missing/incompatible system tar.

Source

Thrown at scripts/verify_npm_release_assets.mjs:48

const tarballPaths = new Map();

function extractPackageJson(tarballPath) {
  return extractJsonFromTarball(tarballPath, "package/package.json");
}

function extractDistPackageJson(tarballPath) {
  return extractJsonFromTarball(tarballPath, "package/dist/package.json");
}

function extractJsonFromTarball(tarballPath, packageJsonPath) {
  const workdir = mkdtempSync(path.join(tmpdir(), "headroom-npm-asset-"));
  try {
    const result = spawnSync("tar", ["-xzf", tarballPath, "-C", workdir], {
      encoding: "utf8",
    });
    if (result.status !== 0) {
      throw new Error(
        `tar failed for ${tarballPath}: ${result.stderr || result.stdout || "unknown error"}`,
      );
    }
    return JSON.parse(readFileSync(path.join(workdir, packageJsonPath), "utf8"));
  } finally {
    rmSync(workdir, { recursive: true, force: true });
  }
}

function assertNoFileDependencies(pkg) {
  for (const field of ["dependencies", "peerDependencies", "optionalDependencies"]) {
    for (const [name, spec] of Object.entries(pkg[field] || {})) {
      if (typeof spec === "string" && (spec.startsWith("file:") || spec.includes("release-assets"))) {
        throw new Error(`${pkg.name} has non-portable ${field}.${name} spec: ${spec}`);
      }
    }
  }
}

View on GitHub (pinned to 322425c43b)

Solutions

  1. Sanity-check the tarball by hand: `tar -tzf <tarball> | head` — if that fails, the archive is corrupt; rebuild it.
  2. Confirm `tar` exists on PATH in the environment running the script (`which tar`); in slim Docker images install it (`apk add tar` / `apt-get install tar`).
  3. On macOS/BSD-tar issues, run under GNU tar (`gtar`) or the Node implementation the script could use (e.g., node-tar) if portable.
  4. If status is null, also log `result.error` — spawnSync puts the spawn failure there, not in stderr.

Example fix

// before
const result = spawnSync("tar", ["-xzf", tarballPath, "-C", workdir], { encoding: "utf8" });
if (result.status !== 0) {
  throw new Error(`tar failed for ${tarballPath}: ${result.stderr || result.stdout || "unknown error"}`);
}

// after: surface the spawn error too
if (result.error || result.status !== 0) {
  throw new Error(
    `tar failed for ${tarballPath}: ${result.error?.message || result.stderr || result.stdout || "unknown error"}`,
  );
}
Defensive patterns

Strategy: try-catch

Validate before calling

import { execFileSync } from "node:child_process";

function tarballIntact(tarballPath) {
  try {
    execFileSync("tar", ["-tzf", tarballPath], { stdio: "ignore" });
    return true;
  } catch {
    return false;
  }
}
// assert tarballIntact(p) before extractJsonFromTarball(p, ...)

Try / catch

try {
  const pkg = extractJsonFromTarball(tarballPath, "package/dist/package.json");
} catch (err) {
  if (/tar failed/.test(err.message)) {
    // distinguish corrupt archive vs missing binary before retrying
    if (!tarballIntact(tarballPath)) throw new Error(`corrupt tarball: ${tarballPath}`);
    throw new Error(`tar unavailable or incompatible: ${err.message}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: The tarball is truncated or not gzip data (interrupted `npm pack`, bad download/copy); `tar` is not on PATH (result.status is null, result.error set, message shows 'unknown error'); platform tar incompatibilities (BSD tar vs GNU tar flags); the temp extraction dir is unwritable.

Common situations: Verifying artifacts that were transferred between CI and a local machine; minimal Docker images lacking tar; macOS default bsdtar behaving differently from GNU tar; parallel runs colliding on tmp space.

Related errors


AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15). Data as JSON: /api/errors/4392e4a4d92c9e35. Report an issue: GitHub.