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

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

Error message

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

What it means

The SHA-256 of the downloaded archive does not match asset.sha256 from the release manifest. This is the cryptographic integrity gate; a mismatch means the bytes are not what the publisher shipped (corruption, MITM on plain HTTP, or a mismatched manifest/asset pair).

Source

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

      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;
        }
        throw error;
      }
    }

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Re-download from the official GitHub release URL over HTTPS.
  2. Verify manually: sha256sum <archive> vs the manifest value to distinguish corruption from a bad release.
  3. If consistently mismatched from the official URL, the release assets are bad — pin a known-good version or re-publish.
Defensive patterns

Strategy: fallback

Validate before calling

import { createHash } from 'node:crypto';
import { readFile } from 'node:fs/promises';
async function sha256(p: string): Promise<string> { return createHash('sha256').update(await readFile(p)).digest('hex'); }
// compare against manifest asset.sha256 before trusting a mirrored archive

Try / catch

try { await hydrateNativeBinary(); } catch (e) { if (/checksum mismatch for/.test(String(e))) { /* fetch from official HTTPS release URL; if it still fails, the release is bad — pin another version */ } throw e; }

Prevention

When it happens

Trigger: hydrateNativeBinary when sha256ForFile(archivePath) !== asset.sha256 — corrupted transfer, mirror serving different bytes, or manifest checksums regenerated against different asset builds.

Common situations: HTTP (not HTTPS) mirrors tampering with artifacts; interrupted downloads resumed incorrectly; release automation uploading assets after writing the manifest.

Related errors


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