can1357/oh-my-pi · error · Error

@oh-my-pi/${pkg}@${version} tarball contained no .node files

Error message

@oh-my-pi/${pkg}@${version} tarball contained no .node files

What it means

After extracting a cross-target natives tarball, refreshCrossNatives counts files matching `pi_natives.linux-<arch>*.node`; if none matched it throws, meaning the published tarball is malformed or does not ship natives for the requested architecture. This guards against silently proceeding with no cross natives bundled.

Source

Thrown at packages/metaharness/src/tb/agent.ts:44

 * leaf is the artifact real installs load, so it is the ground truth for
 * embedding; an unpublished working-tree version fails instead of risking
 * loader/API skew.
 */
async function refreshCrossNatives(arches: GuestArch[], version: string): Promise<void> {
	for (const arch of arches) {
		if (process.platform === "linux" && process.arch === arch) continue;
		const pkg = `pi-natives-linux-${arch}`;
		const response = await fetch(`https://registry.npmjs.org/@oh-my-pi/${pkg}/-/${pkg}-${version}.tgz`);
		if (!response.ok) throw new Error(`Fetching @oh-my-pi/${pkg}@${version} failed: HTTP ${response.status}`);
		const archive = new Bun.Archive(await response.arrayBuffer());
		let extracted = 0;
		for (const [entry, file] of await archive.files()) {
			const name = path.posix.basename(entry);
			if (!name.startsWith(`pi_natives.linux-${arch}`) || !name.endsWith(".node")) continue;
			await Bun.write(path.join(NATIVES_DIR, name), file);
			extracted++;
		}
		if (extracted === 0) throw new Error(`@oh-my-pi/${pkg}@${version} tarball contained no .node files`);
	}
}

/** Build and cache self-contained omp binaries for the selected guest architectures. */
export async function prepareAgentBinaries(opts: {
	arches: GuestArch[];
	cacheDir: string;
	rebuild: boolean;
}): Promise<AgentBinaries> {
	const manifest = (await Bun.file(path.join(CODING_AGENT_DIR, "package.json")).json()) as { version?: unknown };
	if (typeof manifest.version !== "string" || manifest.version.length === 0) {
		throw new Error("packages/coding-agent/package.json has no valid version");
	}

	const arches = [...new Set(opts.arches)];
	const cached: Partial<Record<GuestArch, string>> = {};
	for (const arch of arches) {
		cached[arch] = path.join(opts.cacheDir, `omp-linux-${arch}-${manifest.version}`);

View on GitHub (pinned to 9690622007)

Solutions

  1. Inspect the tarball contents (`tar tzf <pkg>-<version>.tgz`) to see what was actually published
  2. Republish the platform package with correctly built .node binaries
  3. If the naming convention changed, update the filter in refreshCrossNatives to match the new names
  4. Verify you requested a supported GuestArch that the package actually ships

Example fix

// before
await refreshCrossNatives(["riscv64"], version); // package doesn't ship riscv64 natives
// after
const supported: GuestArch[] = ["x64", "arm64"];
await refreshCrossNatives(arches.filter(a => supported.includes(a)), version);
Defensive patterns

Strategy: validation

Validate before calling

// inspect the tarball before relying on it
const res = await fetch(tarballUrl);
const archive = new Bun.Archive(await res.arrayBuffer());
const hasNatives = (await archive.files()).some(([e]) =>
  path.posix.basename(e).startsWith(`pi_natives.linux-${arch}`) && e.endsWith(".node"));
if (!hasNatives) throw new Error(`${pkg}@${version} ships no ${arch} natives`);

Try / catch

try {
  await refreshCrossNatives(arches, version);
} catch (err) {
  if (err instanceof Error && err.message.includes("tarball contained no .node files")) {
    throw new Error(`bad publish of @oh-my-pi/${pkg}@${version}; pin a known-good version`);
  }
  throw err;
}

Prevention

When it happens

Trigger: The downloaded `@oh-my-pi/pi-natives-linux-<arch>` tarball contained zero `.node` files whose basename starts with `pi_natives.linux-<arch>` — e.g. the package published an empty/placeholder tarball, or the archive layout changed so `.node` files sit elsewhere or under different names.

Common situations: A newly published platform package version shipped without built binaries; npm served a stale/cached empty tarball; native file naming convention changed upstream so the `startsWith` filter no longer matches; wrong arch requested for a package that does not build that target.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/f5b8938b1a592bf4. Report an issue: GitHub.