{"record":{"id":"30470efec3f819fc","repo":"affaan-m/ECC","slug":"nasiko-archive-is-truncated","errorCode":null,"errorMessage":"Nasiko archive is truncated.","messagePattern":"Nasiko archive is truncated\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/lib/nasiko-release.js","lineNumber":96,"sourceCode":"}\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  while (offset + 512 <= tar.length) {\n    const header = tar.subarray(offset, offset + 512);\n    if (header.every(byte => byte === 0)) break;\n    const name = readTarString(header, 0, 100);\n    const prefix = readTarString(header, 345, 155);\n    const type = String.fromCharCode(header[156] || 48);\n    const rawSize = readTarString(header, 124, 12).trim();\n    const size = Number.parseInt(rawSize || '0', 8);\n    const start = offset + 512;\n    const end = start + size;\n    if (!Number.isSafeInteger(size) || size < 0 || end > tar.length) throw new Error('Nasiko archive is truncated.');\n    const payload = tar.subarray(start, end);\n    const isBinary = !prefix && name === expectedName && (type === '0' || type === '\\0');\n    const isAppleDouble = !prefix && name === `._${expectedName}` && type === '0' && size <= 1024 * 1024;\n    const isPaxMetadata = !prefix && name === `PaxHeader/${expectedName}` && type === 'x' && size <= 64 * 1024\n      && !/(?:^|\\n)(?:path|linkpath)=/i.test(payload.toString('utf8'));\n    if (isBinary && !binary && size > 0 && size <= MAX_BINARY_BYTES) binary = Buffer.from(payload);\n    else if (!isAppleDouble && !isPaxMetadata) throw new Error('Unsafe Nasiko archive: expected exactly one bounded regular binary file.');\n    offset = start + Math.ceil(size / 512) * 512;\n  }\n  if (!binary) throw new Error('Unsafe Nasiko archive: expected exactly one bounded regular binary file.');\n  return binary;\n}\n\nfunction fetchBytes(url, options = {}) {\n  const parsed = new URL(url);\n  if (parsed.origin !== REGISTRY_ORIGIN || parsed.protocol !== 'https:') return Promise.reject(new Error('Nasiko download origin is not allowed.'));\n  const maxBytes = options.maxBytes || MAX_ARCHIVE_BYTES;\n  return new Promise((resolve, reject) => {","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/affaan-m/ECC/blob/06c5e118c4d3e6c3b7f9445f973a2194c82de193/scripts/lib/nasiko-release.js#L78-L114","documentation":"While walking the gunzipped tar in extractQualifiedTarGzip (scripts/lib/nasiko-release.js), each 512-byte header's octal size field is parsed and the entry's end offset (header + payload) is compared against the buffer length. If an entry claims more bytes than remain, the archive is truncated relative to its own headers and parsing stops with this error.","triggerScenarios":"For any tar entry: start + size > tar.length, or a size field that parses to NaN/negative. Causes: the gzip stream was cut short but still inflated partially, the tar was assembled with a wrong size header, or bytes were dropped after decompression.","commonSituations":"Interrupted downloads that still passed digest checks because the digest was of a different (truncated) artifact than expected; hand-rolled tar generation with incorrect octal size padding; tools that append data after the two zero end-blocks misaligning the walk.","solutions":["Re-run the install to fetch a fresh, complete layer","Verify the artifact manually: download the layer, `gunzip` it, and run `tar -tvf` to confirm the tar itself is intact","If you produce the archive, ensure sizes are correct zero-padded octal and the stream is fully flushed before digesting"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await installNasiko({ version: 'v0.1.0' });\n} catch (error) {\n  if (/archive is truncated/.test(String(error.message))) {\n    // A header claimed more payload bytes than the buffer holds. Re-fetch once;\n    // if reproducible, inspect with `tar -tvf` after gunzip and report a\n    // packaging defect upstream.\n  }\n  throw error;\n}","preventionTips":["Verify tar integrity (`tar -tvf`) as a release-pipeline step before digesting","Write archives atomically: finish the tar stream, then compute and pin digests","Use zero-padded octal size fields when generating headers by hand"],"tags":["tar","archive","corruption"],"backgroundTag":"corrupt-tar-archive","analyzedSha":"06c5e118c4d3e6c3b7f9445f973a2194c82de193","analyzedAt":"2026-08-18T11:27:13.915Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}