Hmbown/CodeWhale · error · Error

npm pack did not return package metadata

Error message

npm pack did not return package metadata

What it means

Thrown by parsePackJson() in the npm wrapper smoke test after `npm pack --json --pack-destination <dir>` returned completely empty stdout. npm 7+ prints a JSON array of packed-tarball metadata to stdout; an empty string means that JSON report never arrived. The smoke script then cannot learn the .tgz filename it just built.

Source

Thrown at scripts/release/npm-wrapper-smoke.js:125

    }
  });

  return new Promise((resolve, reject) => {
    server.once("error", reject);
    server.listen(0, "127.0.0.1", () => {
      const address = server.address();
      resolve({
        baseUrl: `http://127.0.0.1:${address.port}/`,
        server,
      });
    });
  });
}

function parsePackJson(stdout) {
  const trimmed = stdout.trim();
  if (!trimmed) {
    throw new Error("npm pack did not return package metadata");
  }
  const parsed = JSON.parse(trimmed);
  const first = Array.isArray(parsed) ? parsed[0] : parsed;
  if (!first || !first.filename) {
    throw new Error(`npm pack metadata did not include a filename: ${trimmed}`);
  }
  return first.filename;
}

async function main() {
  const tempRoot = await fsp.mkdtemp(path.join(os.tmpdir(), "codewhale-npm-smoke-"));
  const suppliedAssetsDir = String(
    process.env.CODEWHALE_SMOKE_ASSETS_DIR || "",
  ).trim();
  const releaseAssetsDir = suppliedAssetsDir
    ? path.resolve(suppliedAssetsDir)
    : path.join(tempRoot, "release-assets");
  const packDir = path.join(tempRoot, "pack");

View on GitHub (pinned to 8880682c63)

Solutions

  1. Check `npm --version` in the same shell/CI image; upgrade to npm >= 7 (`npm i -g npm@latest` or use Node 16+)
  2. Run `npm pack --json --pack-destination /tmp/pack` by hand in the package directory and confirm the JSON array prints to stdout
  3. Inspect .npmrc and NPM_CONFIG_* env for loglevel/silent settings that suppress stdout
  4. Rerun the smoke script and read the retained workspace path printed on failure for clues

Example fix

// before
const pack = await runCommand('npm', ['pack', '--json', '--pack-destination', packDir], { capture: true, cwd: packageDir, env });
const tarball = path.join(packDir, parsePackJson(pack.stdout));

// after - gate on npm major version first
const versionOut = await runCommand('npm', ['--version'], { capture: true });
const major = Number(versionOut.stdout.trim().split('.')[0]);
if (!(major >= 7)) {
  throw new Error(`npm >= 7 required for pack --json output, found ${versionOut.stdout.trim()}`);
}
const pack = await runCommand('npm', ['pack', '--json', '--pack-destination', packDir], { capture: true, cwd: packageDir, env });
const tarball = path.join(packDir, parsePackJson(pack.stdout));
Defensive patterns

Strategy: validation

Validate before calling

import { execFileSync } from 'node:child_process';
const [major] = execFileSync('npm', ['--version'], { encoding: 'utf8' }).trim().split('.').map(Number);
if (!(major >= 7)) {
  throw new Error(`npm >= 7 required for pack --json output, found ${major}`);
}

Try / catch

try {
  tarball = path.join(packDir, parsePackJson(pack.stdout));
} catch (err) {
  console.error('npm stdout:', JSON.stringify(pack.stdout));
  console.error('npm stderr:', pack.stderr);
  throw err;
}

Prevention

When it happens

Trigger: Running scripts/release/npm-wrapper-smoke.js with npm < 7 (no --json report), with npm configured silent (loglevel=silent / --silent), or in an environment where runCommand() only captures stdout while npm wrote its output elsewhere (e.g., output redirected or swallowed by a wrapper).

Common situations: CI images pinned to legacy Node 14/npm 6; a local .npmrc with loglevel=quiet; a broken package.json making npm bail with output only on stderr while exit codes are ignored.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/15739416ecea9ab5. Report an issue: GitHub.