can1357/oh-my-pi · error · Error

Embedded addon archive missing: ${[...pending.keys()].join("

Error message

Embedded addon archive missing: ${[...pending.keys()].join(", ")}

What it means

After walking the entire tar stream, the loader verifies that every manifest file it decided to extract (files absent or stale on disk) was actually present in the archive. If any pending filenames were never seen, it throws listing the missing names rather than leaving a partial extraction that would fail at require() time.

Source

Thrown at packages/natives/native/loader-state.js:548

			throw new Error(`Unsupported embedded addon archive entry type ${typeflag}: ${filename}`);
		}

		const file = pending.get(filename);
		if (file) {
			if (typeof file.size === "number" && file.size !== size) {
				throw new Error(`Embedded addon size mismatch for ${filename}: expected ${file.size}, got ${size}`);
			}
			const targetPath = path.join(targetDir, filename);
			writeEmbeddedAddonFile(targetPath, archive.subarray(offset, offset + size));
			pending.delete(filename);
			writtenPaths.push(targetPath);
		}

		offset += Math.ceil(size / 512) * 512;
	}

	if (pending.size > 0) {
		throw new Error(`Embedded addon archive missing: ${[...pending.keys()].join(", ")}`);
	}

	return writtenPaths;
}

function maybeExtractEmbeddedAddon(ctx, errors) {
	if (!ctx.isCompiledBinary || !embeddedAddon) return null;
	if (embeddedAddon.platformTag !== ctx.platformTag || embeddedAddon.version !== ctx.packageVersion) return null;

	const selectedEmbeddedFile = selectEmbeddedAddonFile(ctx.selectedVariant);
	if (!selectedEmbeddedFile) return null;
	const targetPath = path.join(ctx.versionedDir, selectedEmbeddedFile.filename);

	startupMarker("native:extractEmbeddedAddon:start");
	try {
		prepareNativeVersionDir(ctx.versionedDir);
	} catch (err) {
		const message = err instanceof Error ? err.message : String(err);

View on GitHub (pinned to 9690622007)

Solutions

  1. Reinstall omp / rebuild the binary so the embedded manifest and archive match.
  2. Verify the archive contents with tar -tzf against the manifest's filenames.
  3. Fix the packaging script to derive the manifest from the actual files placed into the tar.
  4. Check for filename case or directory-prefix mismatches between manifest and archive entries.
Defensive patterns

Strategy: validation

Validate before calling

import { execFileSync } from "node:child_process";
function assertArchiveCoversManifest(archivePath, files) {
  const entries = new Set(
    execFileSync("tar", ["-tzf", archivePath], { encoding: "utf8" }).split("\n").filter(Boolean)
  );
  const missing = files.map(f => f.filename).filter(name => !entries.has(name));
  if (missing.length) throw new Error(`Embedded addon archive missing: ${missing.join(", ")}`);
}

Try / catch

try {
  extractEmbeddedAddonArchive({ archivePath, files, targetDir });
} catch (err) {
  if (err.message.startsWith("Embedded addon archive missing:")) {
    // treat install as broken; prompt user to reinstall
  } else throw err;
}

Prevention

When it happens

Trigger: extractEmbeddedAddonArchive completes the tar walk but pending still contains entries — i.e. the manifest listed files (e.g. 'pi_natives-darwin-arm64.node') that do not exist as entries in the embedded .tar.gz.

Common situations: A build packaged an archive subset while baking the full file manifest; the archive was truncated such that trailing entries were never reached (tar usually ends at the first zero block); manifest filenames differ from archive entry names (path or case mismatch).

Related errors


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