{"record":{"id":"d692388bc59aa6b8","repo":"affaan-m/ECC","slug":"nasiko-manifest-is-not-valid-json","errorCode":null,"errorMessage":"Nasiko manifest is not valid JSON.","messagePattern":"Nasiko manifest is not valid JSON\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/nasiko-release.js","lineNumber":62,"sourceCode":"  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\nfunction readTarString(block, offset, length) {\n  return block.subarray(offset, offset + length).toString('utf8').replace(/\\0.*$/, '');\n}\n\nfunction readTarOctal(block, offset, length) {","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/nasiko-release.js#L44-L80","documentation":"validateManifest parses the OCI manifest bytes as UTF-8 JSON and throws this error when JSON.parse fails. The library requires a syntactically valid JSON manifest before it inspects schemaVersion and layers. This guard exists so malformed responses are reported clearly rather than as opaque parse crashes downstream.","triggerScenarios":"validateManifest is called with bytes that are not valid JSON — e.g. an HTML error page from the registry, empty body, gzip bytes mistakenly passed instead of the decoded manifest, or truncated response.","commonSituations":"Registry returns 404/403 HTML instead of the manifest, an auth-redirect page is captured, the wrong URL is fetched (tag vs blob), or a network proxy injects content.","solutions":["Log bytes.toString('utf8').slice(0, 200) to see what was actually received — it usually reveals an HTML error page or empty body.","Check the HTTP status code of the manifest fetch before passing bytes to validateManifest.","Confirm the fetch URL points at the manifest endpoint with the correct Accept header (application/vnd.oci.image.manifest.v1+json).","Ensure the response was not left gzip-encoded (Content-Encoding) — decode before validating."],"exampleFix":"// before\nvalidateManifest(await res.arrayBuffer());\n// after\nconst res = await fetch(manifestUrl, { headers: { Accept: 'application/vnd.oci.image.manifest.v1+json' } });\nif (!res.ok) throw new Error(`manifest fetch failed: HTTP ${res.status}`);\nconst bytes = Buffer.from(await res.arrayBuffer());\nJSON.parse(bytes.toString('utf8')); // fail with real parse error if still invalid\nvalidateManifest(bytes);","handlingStrategy":"try-catch","validationCode":"const text = bytes.toString('utf8').trim();\nif (!text.startsWith('{')) throw new Error(`manifest not JSON, starts with: ${text.slice(0, 80)}`);\nJSON.parse(text);","typeGuard":"const looksLikeJson = (b) => b.toString('utf8').trimStart().startsWith('{');","tryCatchPattern":"try { installNasiko(opts); } catch (e) { if (e.message.includes('not valid JSON')) console.error('registry returned non-JSON; check URL/status/accept header'); throw e; }","preventionTips":["Check HTTP status and Content-Type of the manifest response before parsing.","Send the correct OCI Accept header on manifest requests.","Log the first bytes of any non-JSON response to diagnose registry auth/redirect issues."],"tags":["json","parsing","oci"],"backgroundTag":"json-parse-error","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"}