Yeachan-Heo/oh-my-codex · error · Error

[native-assets] downloaded archive size mismatch for ${asset

Error message

[native-assets] downloaded archive size mismatch for ${asset.archive}

What it means

The downloaded release archive's on-disk size does not match the size declared in the release manifest. This is the first integrity gate after downloadFile; a size mismatch means a truncated or altered download and the asset is rejected before checksum verification/extraction.

Source

Thrown at src/cli/native-assets.ts:735

  const extractedBinaryPath = join(tempRoot, 'native-binary');

  try {
    for (let index = 0; index < assets.length; index += 1) {
      const asset = assets[index]!;
      const archivePath = join(tempRoot, asset.archive);
      const cachedBinaryPath = resolveCachedNativeBinaryPath(
        product,
        version,
        platform,
        arch,
        env,
        inferNativeAssetLibc(asset),
      );
      try {
        await downloadFile(asset.download_url, archivePath);
        const archiveStat = await stat(archivePath);
        if (typeof asset.size === 'number' && asset.size > 0 && archiveStat.size !== asset.size) {
          throw new Error(`[native-assets] downloaded archive size mismatch for ${asset.archive}`);
        }
        const digest = await sha256ForFile(archivePath);
        if (digest !== asset.sha256) {
          throw new Error(`[native-assets] checksum mismatch for ${asset.archive}`);
        }

        const archiveEntries = await inspectNativeArchive(archivePath);
        const archiveBinary = selectNativeArchiveBinary(archiveEntries, asset.binary_path);
        await writeSelectedNativeArchiveMember(archivePath, archiveBinary.path, extractedBinaryPath);

        const published = await publishManagedNativeBinary(extractedBinaryPath, cachedBinaryPath, platform, env);
        if (published) return published;
        throw new Error(`[native-assets] cache publication verification failed for ${cachedBinaryPath}`);
      } catch (error) {
        if (index < assets.length - 1 && isUnavailableArchiveError(error)) {
          await rm(archivePath, { force: true });
          await rm(extractedBinaryPath, { force: true });
          continue;

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Delete the partial archive (the library also cleans on retry) and re-run hydration on a stable network.
  2. Bypass/fix truncating proxies; verify by curl-ing the asset URL and comparing Content-Length with the manifest.
  3. If the release itself is bad, report/re-publish the manifest+assets so sizes agree.
Defensive patterns

Strategy: retry

Validate before calling

async function sizeMatches(url: string, expected: number): Promise<boolean> { const r = await fetch(url, { method: 'HEAD' }); return r.ok && Number(r.headers.get('content-length')) === expected; }

Try / catch

try { await hydrateNativeBinary(); } catch (e) { if (/archive size mismatch/.test(String(e))) { /* re-download on stable network / check proxy truncation */ } throw e; }

Prevention

When it happens

Trigger: hydrateNativeBinary downloading an asset whose manifest-listed size is a positive number but stat(archivePath).size differs — truncated transfers through proxies, HTML error pages saved instead of the archive, or a manifest published with stale sizes.

Common situations: Corporate proxies truncating large binaries; mirrors whose assets differ from upstream; releases where the manifest was regenerated without re-uploading assets.

Related errors


AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27). Data as JSON: /api/errors/d9da86d8b9a72fbf. Report an issue: GitHub.