{"record":{"id":"665aa726c2a27813","repo":"affaan-m/ECC","slug":"label-digest-mismatch-expected-expecteddiges","errorCode":null,"errorMessage":"${label} digest mismatch: expected ${expectedDigest}, got ${actual}.","messagePattern":"(.+?) digest mismatch: expected (.+?), got (.+?)\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"scripts/lib/nasiko-release.js","lineNumber":57,"sourceCode":"\nfunction getQualifiedRelease(version, platform = process.platform, architecture = process.arch) {\n  if (!/^v\\d+\\.\\d+\\.\\d+$/.test(String(version || ''))) {\n    throw new Error('Nasiko installation requires a pinned version such as v0.1.0; latest is not allowed.');\n  }\n  const normalized = normalizePlatform(platform, architecture);\n  const qualification = QUALIFIED_RELEASES[version]?.[`${normalized.os}/${normalized.arch}`];\n  if (!qualification) throw new Error(`Nasiko ${version} is not qualified for ${normalized.os}/${normalized.arch}.`);\n  return { version, ...normalized, ...qualification, license: LICENSE, sourceUrl: SOURCE_URL };\n}\n\nfunction digestBytes(bytes) {\n  return `sha256:${crypto.createHash('sha256').update(bytes).digest('hex')}`;\n}\n\nfunction assertDigest(bytes, expectedDigest, label) {\n  if (!SHA256_PATTERN.test(expectedDigest)) throw new Error(`${label} has an invalid expected digest.`);\n  const actual = digestBytes(bytes);\n  if (actual !== expectedDigest) throw new Error(`${label} digest mismatch: expected ${expectedDigest}, got ${actual}.`);\n}\n\nfunction validateManifest(bytes) {\n  let manifest;\n  try { manifest = JSON.parse(bytes.toString('utf8')); } catch (_error) { throw new Error('Nasiko manifest is not valid JSON.'); }\n  if (manifest.schemaVersion !== 2 || !Array.isArray(manifest.layers) || manifest.layers.length !== 1) {\n    throw new Error('Nasiko manifest must contain exactly one OCI layer.');\n  }\n  const layer = manifest.layers[0];\n  if (layer.mediaType !== 'application/gzip' || !SHA256_PATTERN.test(layer.digest)) {\n    throw new Error('Nasiko manifest layer is not a qualified gzip artifact.');\n  }\n  if (!Number.isSafeInteger(layer.size) || layer.size <= 0 || layer.size > MAX_ARCHIVE_BYTES) {\n    throw new Error('Nasiko manifest layer size is outside the allowed range.');\n  }\n  return { digest: layer.digest, size: layer.size };\n}\n","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/nasiko-release.js#L39-L75","documentation":"After confirming the expected digest string is well-formed, assertDigest computes the actual SHA-256 of the supplied bytes and compares it to the expected value. This error means the content does not match its declared digest — the data is corrupted, tampered with, or the wrong file was supplied. It is the library's supply-chain integrity check.","triggerScenarios":"installNasiko passes bytes (e.g. a downloaded layer or archive) plus its declared digest to assertDigest, and sha256(bytes) !== expectedDigest. E.g. a partially downloaded file, a re-pushed image tag, or an edited manifest.","commonSituations":"Interrupted downloads, a registry tag was overwritten with new content, a proxy or mirror rewrote the artifact, or the manifest was hand-edited without updating the digest.","solutions":["Re-download/re-fetch the artifact and retry — the most common cause is a truncated or corrupted transfer.","Verify the digest against the upstream publisher's signed manifest to confirm which side is stale.","If the artifact legitimately changed, update the expectedDigest to the freshly computed value and re-run.","Clear any intermediate cache or mirror that may have served a stale blob."],"exampleFix":"// before\nassertDigest(archiveBytes, manifestDigest, 'manifest');\n// after\nconst actual = `sha256:${crypto.createHash('sha256').update(archiveBytes).digest('hex')}`;\nif (actual !== manifestDigest) {\n  console.error(`stale artifact? expected ${manifestDigest}, got ${actual}; refetching...`);\n  archiveBytes = await refetchAndVerify();\n}\nassertDigest(archiveBytes, manifestDigest, 'manifest');","handlingStrategy":"validation","validationCode":"const actual = `sha256:${crypto.createHash('sha256').update(bytes).digest('hex')}`;\nif (actual !== expectedDigest) throw new Error(`artifact corrupted: ${actual} != ${expectedDigest}; refetch`);","typeGuard":"null","tryCatchPattern":"try { installNasiko(opts); } catch (e) { if (e.message.includes('digest mismatch')) { await refetchArtifact(); return installNasiko(opts); } throw e; }","preventionTips":["Always pin artifacts by digest, never by mutable tag.","Verify downloads immediately after fetch, before caching.","Re-download once automatically on mismatch before surfacing the error."],"tags":["checksum","integrity","supply-chain"],"backgroundTag":"checksum-mismatch","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}