headroomlabs-ai/headroom · error · Error

Expected npm pack to produce ${tarballPath}

Error message

Expected npm pack to produce ${tarballPath}

What it means

Thrown by assertTarballBuilt() after the script runs `npm pack` for the SDK package. It expects a tarball named `<name>-<version>.tgz` in the assets directory and throws when that exact file is absent. The build treats a missing tarball as a hard failure because downstream steps (dependency rewrites, verification) all consume that file.

Source

Thrown at scripts/build_npm_release_assets.mjs:157

  const packageJsonPath = path.join(openClawDir, "package.json");
  const pkg = readJson(packageJsonPath);
  pkg.dependencies = pkg.dependencies || {};
  pkg.dependencies["headroom-ai"] = spec;
  writeJson(packageJsonPath, pkg);
}

function rewriteOpenClawLocalDependency(sdkTarballPath) {
  rewriteOpenClawDependency(relativeFileSpec(openClawDir, sdkTarballPath));
}

function rewriteOpenClawReleaseDependency() {
  rewriteOpenClawDependency(`^${version}`);
}

function assertTarballBuilt(name) {
  const tarballPath = path.join(assetsDir, `${name}-${version}.tgz`);
  if (!existsSync(tarballPath)) {
    throw new Error(`Expected npm pack to produce ${tarballPath}`);
  }
  return tarballPath;
}

try {
  ensureEmptyAssetsDir();

  if (!flags.has("--skip-install")) {
    runNpm(["ci"], sdkDir);
  }
  runNpm(["run", "build"], sdkDir);
  runNpm(["version", version, "--no-git-tag-version", "--allow-same-version"], sdkDir);
  runNpm(["pack", "--pack-destination", assetsDir], sdkDir);
  const sdkTarballPath = assertTarballBuilt("headroom-ai");

  rewriteOpenClawLocalDependency(sdkTarballPath);
  if (!flags.has("--skip-install")) {
    runNpm(

View on GitHub (pinned to 322425c43b)

Solutions

  1. List the assets directory and compare the actual tarball filename with `<name>-<version>.tgz`; if the version differs, rerun the script with the version npm stamped (`npm pkg get version` in the SDK dir).
  2. If the package is scoped, confirm the lookup uses the flattened filename npm pack produces (scope-name-version.tgz) or pass the flattened name to assertTarballBuilt.
  3. Confirm the `npm pack` invocation includes `--pack-destination <assetsDir>` and that runNpm checks a nonzero exit code.
  4. Delete the assets directory (ensureEmptyAssetsDir recreates it) and rerun the full script so version stamping and packing happen in one pass.

Example fix

// before
const tarballPath = path.join(assetsDir, `${name}-${version}.tgz`);
if (!existsSync(tarballPath)) {
  throw new Error(`Expected npm pack to produce ${tarballPath}`);
}

// after: fall back to the flattened scoped name npm pack actually emits
const packedName = name.replace(/^@/, "").replace("/", "-");
let tarballPath = path.join(assetsDir, `${packedName}-${version}.tgz`);
if (!existsSync(tarballPath)) {
  tarballPath = path.join(assetsDir, `${name}-${version}.tgz`);
}
if (!existsSync(tarballPath)) {
  throw new Error(`Expected npm pack to produce ${tarballPath}`);
}
Defensive patterns

Strategy: validation

Validate before calling

import { existsSync, readdirSync } from "node:fs";
import path from "node:path";

function findPackedTarball(assetsDir, name, version) {
  const candidates = [
    `${name}-${version}.tgz`,
    `${name.replace(/^@/, "").replace("/", "-")}-${version}.tgz`,
  ];
  for (const file of candidates) {
    if (existsSync(path.join(assetsDir, file))) return path.join(assetsDir, file);
  }
  return null;
}
// call before assertTarballBuilt; log readdirSync(assetsDir) when null

Prevention

When it happens

Trigger: Running scripts/build_npm_release_assets.mjs with a version that does not match the version `npm version` stamped into package.json; a scoped package whose tarball filename uses the flattened form (`@scope/name` becomes `scope-name-x.y.z.tgz`) while `name` is looked up unflattened; `npm pack` writing to a different destination than assetsDir; or `npm pack` failing quietly (runNpm not checking stderr).

Common situations: Version drift between the CLI argument and package.json; rerunning the script after a partially failed run left assetsDir in a bad state; npm config (`pack-destination`) or workspaces changing where the tarball lands; package.json `name` edited between runs.

Related errors


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