affaan-m/ECC · error

Nasiko archive size mismatch.

Error message

Nasiko archive size mismatch.

What it means

Thrown after downloading the Nasiko tar.gz archive when the byte length of the downloaded blob does not equal the layer size declared in the OCI image manifest. This is an integrity gate before digest verification, ensuring truncated or padded downloads never reach extraction.

Solutions

  1. Retry the download; transient truncation is the most common cause.
  2. Verify the registry origin and mirror are consistent — compare manifest layer size against the blob endpoint directly.
  3. Clear any proxy/cache layer between the client and REGISTRY_ORIGIN and retry.
  4. Check MAX_ARCHIVE_BYTES handling: ensure the fetch implementation doesn't silently truncate at the maxBytes limit instead of erroring.

Example fix

// before
const archiveBytes = await retrieve(url, { maxBytes: MAX_ARCHIVE_BYTES });
// after (retry truncated downloads)
let archiveBytes;
for (let i = 0; i < 3; i++) {
  archiveBytes = await retrieve(url, { maxBytes: MAX_ARCHIVE_BYTES });
  if (archiveBytes.length === layer.size) break;
}
Defensive patterns

Strategy: retry

Validate before calling

const res = await fetch(blobUrl);
const buf = Buffer.from(await res.arrayBuffer());
if (buf.length !== expectedLayerSize) throw new Error('retry: truncated blob download');

Type guard

function isCompleteDownload(bytes, expectedSize) {
  return bytes instanceof Uint8Array && bytes.length === expectedSize;
}

Try / catch

try {
  await installNasiko({ version });
} catch (e) {
  if (e.message === 'Nasiko archive size mismatch.') {
    await new Promise(r => setTimeout(r, 1000));
    await installNasiko({ version }); // retry transient truncation
  } else throw e;
}

Prevention

When it happens

Trigger: fetchBytes (or dependencies.fetchBytes) returns a buffer whose .length differs from validateManifest(manifestBytes).layer.size — e.g. a truncated response, a proxy or registry serving a different/rewritten blob, or a manifest from the registry that disagrees with the actual blob size.

Common situations: Flaky network or interrupted download behind a misbehaving proxy; registry storage corruption; CDN/blob middleware that modifies payloads; pointing at a mirror whose manifests and blobs are out of sync.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/b31b9987e09ab982. Report an issue: GitHub.

Appendix: source

Thrown at scripts/lib/nasiko-release.js:405

  if (!options.yes) throw new Error('Nasiko installation requires explicit --yes consent.');
  fs.mkdirSync(installDirectory, { recursive: true, mode: 0o755 });
  assertPrivateInstallDirectory(installDirectory);
  const releaseLock = acquireLifecycleLock(installDirectory);
  const metadataPath = metadataPathFor(destination);
  let destinationOwned = false;
  let metadataOwned = false;
  try {
    const existing = inspectInstalledNasiko(destination);
    if (existing.installed) {
      if (existing.qualified && existing.version === version) return { ...plan, dryRun: false, installed: true, reused: true };
      throw new Error('An unqualified or incompatible Nasiko executable or receipt already exists at the destination.');
    }
    const retrieve = dependencies.fetchBytes || fetchBytes;
    const manifestBytes = await retrieve(`${REGISTRY_ORIGIN}/v2/${REPOSITORY}/manifests/${release.manifestDigest}`, { accept: 'application/vnd.oci.image.manifest.v1+json', maxBytes: MAX_MANIFEST_BYTES });
    assertDigest(manifestBytes, release.manifestDigest, 'Nasiko manifest');
    const layer = validateManifest(manifestBytes);
    const archiveBytes = await retrieve(`${REGISTRY_ORIGIN}/v2/${REPOSITORY}/blobs/${layer.digest}`, { maxBytes: MAX_ARCHIVE_BYTES });
    if (archiveBytes.length !== layer.size) throw new Error('Nasiko archive size mismatch.');
    assertDigest(archiveBytes, layer.digest, 'Nasiko archive');
    const binary = (dependencies.extractBinary || extractQualifiedTarGzip)(archiveBytes, release.binaryName);
    assertDigest(binary, release.binaryDigest, 'Nasiko binary');
    if (dependencies.beforePublish) dependencies.beforePublish(destination);
    const descriptor = fs.openSync(destination, 'wx', 0o700);
    destinationOwned = true;
    try {
      fs.writeFileSync(descriptor, binary);
      fs.fsyncSync(descriptor);
      if (fs.fstatSync(descriptor).size !== binary.length) throw new Error('Published Nasiko binary size mismatch.');
    } finally { fs.closeSync(descriptor); }
    const metadata = { version, platform: release.os, architecture: release.arch, manifestDigest: release.manifestDigest, artifactDigest: layer.digest, binaryDigest: release.binaryDigest, installedPath: destination, license: release.license, sourceUrl: release.sourceUrl };
    (dependencies.writeMetadata || writeMetadataExclusive)(metadataPath, metadata);
    metadataOwned = true;
    return { ...plan, dryRun: false, installed: true, reused: false, artifactDigest: layer.digest };
  } catch (error) {
    if (metadataOwned) fs.rmSync(metadataPath, { force: true });
    if (destinationOwned) fs.rmSync(destination, { force: true });

View on GitHub (pinned to 8321021c54)