{"record":{"id":"b0861bcc30faef4b","repo":"affaan-m/ECC","slug":"label-has-an-invalid-expected-digest","errorCode":null,"errorMessage":"${label} has an invalid expected digest.","messagePattern":"(.+?) has an invalid expected digest\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/nasiko-release.js","lineNumber":55,"sourceCode":"  return { os: osName, arch, binaryName: osName === 'windows' ? 'nasiko.exe' : 'nasiko' };\n}\n\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 };","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/nasiko-release.js#L37-L73","documentation":"assertDigest validates that an expected digest string is well-formed before comparing it against the actual SHA-256 of the provided bytes. The library throws this error when the expectedDigest argument does not match SHA256_PATTERN (a full 'sha256:<64 hex chars>' form). It is a pre-check to fail fast on malformed digests before any hashing work.","triggerScenarios":"Calling assertDigest (directly or via installNasiko) with an expectedDigest that is not a valid 'sha256:' prefixed 64-character hex string — e.g. truncated digest, uppercase hex, wrong algorithm prefix, or a raw hex string without the sha256: prefix.","commonSituations":"A release manifest or CI pipeline stores digests in a different format (bare hex, sha512:, base64), a value was hand-truncated while copying, or an older release artifact schema used a legacy digest format.","solutions":["Print the expectedDigest value and verify it matches /^sha256:[0-9a-f]{64}$/ before passing it in.","Regenerate the digest with the same helper the library uses: `sha256:${crypto.createHash('sha256').update(bytes).digest('hex')}`.","If the source stores bare hex, prefix it with 'sha256:' and lowercase it.","Check whether an upstream tool (skopeo, crane, docker) emits a different format and normalize it on read."],"exampleFix":"// before\nassertDigest(bytes, manifest.layers[0].digest.toUpperCase(), 'layer');\n// after\nconst d = manifest.layers[0].digest;\nif (!/^sha256:[0-9a-f]{64}$/.test(d)) throw new Error('normalize digest first');\nassertDigest(bytes, d, 'layer');","handlingStrategy":"validation","validationCode":"function isValidDigest(d) { return typeof d === 'string' && /^sha256:[0-9a-f]{64}$/.test(d); }\nif (!isValidDigest(expected)) throw new Error('bad digest format before calling installNasiko');","typeGuard":"const isSha256Digest = (v) => typeof v === 'string' && /^sha256:[0-9a-f]{64}$/.test(v);","tryCatchPattern":"try { installNasiko(opts); } catch (e) { if (e.message.includes('invalid expected digest')) { console.error('digest format wrong:', opts.digest); } else throw e; }","preventionTips":["Store digests exactly as produced by sha256sum with a lowercase hex encoding plus 'sha256:' prefix.","Add a schema check (zod/regex) at the config boundary where digests are loaded.","Never hand-edit digest strings; regenerate them from the artifact."],"tags":["validation","crypto","digest"],"backgroundTag":"invalid-argument-format","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"}