{"record":{"id":"d90e45a3a8941371","repo":"affaan-m/ECC","slug":"nasiko-archive-is-invalid-or-exceeds-the-decompres","errorCode":null,"errorMessage":"Nasiko archive is invalid or exceeds the decompressed size limit.","messagePattern":"Nasiko archive is invalid or exceeds the decompressed size limit\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/nasiko-release.js","lineNumber":94,"sourceCode":"function readTarString(block, offset, length) {\n  return block.subarray(offset, offset + length).toString('utf8').replace(/\\0.*$/, '');\n}\n\nfunction readTarOctal(block, offset, length) {\n  const field = block.subarray(offset, offset + length).toString('ascii');\n  const match = /^ *([0-7]+)[ \\0]*$/.exec(field);\n  if (!match) throw new Error('Unsafe Nasiko archive: invalid tar size field.');\n  const size = Number.parseInt(match[1], 8);\n  if (!Number.isSafeInteger(size) || size < 0) {\n    throw new Error('Unsafe Nasiko archive: invalid tar size field.');\n  }\n  return size;\n}\n\nfunction extractQualifiedTarGzip(archiveBytes, expectedName) {\n  let tar;\n  try { tar = zlib.gunzipSync(archiveBytes, { maxOutputLength: MAX_BINARY_BYTES + 2048 }); }\n  catch (_error) { throw new Error('Nasiko archive is invalid or exceeds the decompressed size limit.'); }\n  let offset = 0;\n  let binary = null;\n  let terminated = false;\n  while (offset < tar.length) {\n    if (offset + 512 > tar.length) throw new Error('Unsafe Nasiko archive: truncated tar header.');\n    const header = tar.subarray(offset, offset + 512);\n    if (header.every(byte => byte === 0)) {\n      const terminatorEnd = offset + 1024;\n      if (\n        terminatorEnd > tar.length\n        || !tar.subarray(offset + 512, terminatorEnd).every(byte => byte === 0)\n        || !tar.subarray(terminatorEnd).every(byte => byte === 0)\n      ) {\n        throw new Error('Unsafe Nasiko archive: incomplete terminator or nonzero trailing data.');\n      }\n      terminated = true;\n      break;\n    }","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/nasiko-release.js#L76-L112","documentation":"extractQualifiedTarGzip gunzips the archive with an explicit maxOutputLength of MAX_BINARY_BYTES + 2048 and wraps any gunzip failure in this single error. It is thrown when the input is not valid gzip data or when decompressing would exceed the decompressed-size limit — a guard against corrupt inputs and decompression bombs.","triggerScenarios":"installNasiko (via tests/extraction path) passes bytes to extractQualifiedTarGzip that are not gzip-compressed, are truncated mid-stream, or whose decompressed size exceeds MAX_BINARY_BYTES + 2048, causing zlib.gunzipSync to throw.","commonSituations":"Downloaded artifact is actually plain tar or a text error page (no gzip magic), transfer truncated the file, or a malicious/oversized layer attempts a decompression bomb that the limit correctly rejects.","solutions":["Check the first two bytes of the artifact are 0x1f 0x8b (gzip magic); if not, you are extracting the wrong blob or an error page.","Re-download the artifact — truncation mid-gzip stream is the most frequent cause.","Verify the artifact's actual decompressed size fits under MAX_BINARY_BYTES + 2048; if it legitimately grew, the library limit must be respected — republish a smaller artifact.","Confirm the layer digest verified before extraction so you are not debugging a corrupt blob."],"exampleFix":"// before\nextractQualifiedTarGzip(downloadedBytes, 'bin'); // gunzip fails\n// after\nconst head = downloadedBytes.subarray(0, 2);\nif (!(head[0] === 0x1f && head[1] === 0x8b)) {\n  throw new Error(`not gzip: starts with ${head.toString('hex')} — check download/URL`);\n}\nextractQualifiedTarGzip(downloadedBytes, 'bin');","handlingStrategy":"try-catch","validationCode":"const head = archiveBytes.subarray(0, 2);\nif (!(head[0] === 0x1f && head[1] === 0x8b)) throw new Error('not gzip data');\nconst tar = zlib.gunzipSync(archiveBytes, { maxOutputLength: MAX_BINARY_BYTES + 2048 });","typeGuard":"const isGzip = (b) => b?.length >= 2 && b[0] === 0x1f && b[1] === 0x8b;","tryCatchPattern":"try { installNasiko(opts); } catch (e) { if (e.message.includes('decompressed size limit') || e.message.includes('archive is invalid')) { console.error('bad gzip or bomb; refetch verified artifact'); } throw e; }","preventionTips":["Keep gunzip limits enabled; never bypass maxOutputLength.","Verify layer digest before extraction so corrupt blobs fail earlier.","Monitor artifact decompressed size in the publish pipeline."],"tags":["gzip","decompression","size-limit"],"backgroundTag":"file-size-limit-exceeded","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"}