chenglou/pretext · error · Error

Expected exactly one tarball in ${packDir}, found ${tarballs

Error message

Expected exactly one tarball in ${packDir}, found ${tarballs.length}

What it means

packPackage() in package-smoke-test.ts runs `npm pack` into a temp directory, then asserts that exactly one `.tgz` was produced. It throws on zero or more than one. This protects the smoke test's assumption that the published artifact is a single tarball it can install.

Source

Thrown at scripts/package-smoke-test.ts:38

  if (!keepTemp && succeeded) {
    await rm(tempRoot, { recursive: true, force: true })
  }
}

async function packPackage(): Promise<string> {
  const packDir = path.join(tempRoot, 'pack')
  await mkdir(packDir, { recursive: true })

  run(['npm', 'pack', '--pack-destination', packDir], {
    cwd: root,
    stdout: 'inherit',
    stderr: 'inherit',
  })

  const entries = await readdir(packDir)
  const tarballs = entries.filter(entry => entry.endsWith('.tgz'))
  if (tarballs.length !== 1) {
    throw new Error(`Expected exactly one tarball in ${packDir}, found ${tarballs.length}`)
  }
  return path.join(packDir, tarballs[0]!)
}

async function smokeJavaScriptEsm(tarballPath: string): Promise<void> {
  const projectDir = path.join(tempRoot, 'js-esm')
  await createProject(projectDir, {
    name: 'pretext-package-smoke-js-esm',
    private: true,
    type: 'module',
  })

  await installTarball(projectDir, tarballPath)
  await writeFile(
    path.join(projectDir, 'index.js'),
    [
      "import * as pretext from '@chenglou/pretext'",
      "if (typeof pretext.prepare !== 'function') throw new Error('prepare export missing')",

View on GitHub (pinned to ac49b09b7d)

Solutions

  1. Ensure `dist/` is built before packing (run the build step that emits dist/layout.js + dist/layout.d.ts).
  2. Run `npm pack` manually and inspect what it produces: `npm pack --dry-run` to see the file list.
  3. Confirm package.json has a single name and no nested package manifests that could cause double packing.
  4. Check the temp pack dir printed in the error for leftover `.tgz` artifacts.

Example fix

# before — dist not built, npm pack emits nothing
bun run package-smoke-test

# after
bun run build   # or whichever step emits dist/
bun run package-smoke-test
Defensive patterns

Strategy: validation

Validate before calling

import { readdir } from 'node:fs/promises'

async function expectSingleTarball(packDir: string): Promise<string> {
  const tarballs = (await readdir(packDir)).filter(e => e.endsWith('.tgz'))
  if (tarballs.length !== 1) {
    console.error(`Expected 1 tarball, found ${tarballs.length}. Run \`npm pack --dry-run\` to inspect.`)
    process.exit(1)
  }
  return tarballs[0]!
}

Prevention

When it happens

Trigger: Zero tarballs: `npm pack` wrote nothing (e.g. package not buildable, dist/ missing on a clean checkout). More than one: package.json defines multiple packages or a prior pack left stale `.tgz` files in the pack dir (shouldn't happen since packDir is freshly made, but a misconfigured `files`/`prepack` could).

Common situations: Running the smoke test without building dist/ first (the published entrypoints target dist/layout.js), or running it in a worktree with an unusual package layout.

Related errors


AI-assisted analysis of chenglou/pretext@ac49b09b7d (2026-08-12). Data as JSON: /api/errors/12638ed3a004d1f9. Report an issue: GitHub.