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
- Retry the download; transient truncation is the most common cause.
- Verify the registry origin and mirror are consistent — compare manifest layer size against the blob endpoint directly.
- Clear any proxy/cache layer between the client and REGISTRY_ORIGIN and retry.
- 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
- Retry downloads on flaky networks
- Bypass suspicious proxies/caches when integrity checks fail
- Verify registry mirror sync health
- Cap fetch buffers properly so truncation is explicit, not silent
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
- artifact byte count mismatch
- download length does not match declared size
- download length does not match declared size
- application bundle differs from its bound evidence
- approval evidence must bind exact source, candidate and…
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)