affaan-m/ECC · error

Nasiko archive is invalid or exceeds the decompressed size l

Error message

Nasiko archive is invalid or exceeds the decompressed size limit.

What it means

extractQualifiedTarGzip in scripts/lib/nasiko-release.js inflates the downloaded layer with zlib.gunzipSync and a maxOutputLength cap of MAX_BINARY_BYTES + 2048 (64 MiB + 2 KiB). A gunzip error (bad header, corrupt stream) or output exceeding the cap throws this error. The cap is the decompression-bomb guard: a small gzip payload cannot expand into unbounded memory.

Source

Thrown at scripts/lib/nasiko-release.js:83

  }
  const layer = manifest.layers[0];
  if (layer.mediaType !== 'application/gzip' || !SHA256_PATTERN.test(layer.digest)) {
    throw new Error('Nasiko manifest layer is not a qualified gzip artifact.');
  }
  if (!Number.isSafeInteger(layer.size) || layer.size <= 0 || layer.size > MAX_ARCHIVE_BYTES) {
    throw new Error('Nasiko manifest layer size is outside the allowed range.');
  }
  return { digest: layer.digest, size: layer.size };
}

function readTarString(block, offset, length) {
  return block.subarray(offset, offset + length).toString('utf8').replace(/\0.*$/, '');
}

function extractQualifiedTarGzip(archiveBytes, expectedName) {
  let tar;
  try { tar = zlib.gunzipSync(archiveBytes, { maxOutputLength: MAX_BINARY_BYTES + 2048 }); }
  catch (_error) { throw new Error('Nasiko archive is invalid or exceeds the decompressed size limit.'); }
  let offset = 0;
  let binary = null;
  while (offset + 512 <= tar.length) {
    const header = tar.subarray(offset, offset + 512);
    if (header.every(byte => byte === 0)) break;
    const name = readTarString(header, 0, 100);
    const prefix = readTarString(header, 345, 155);
    const type = String.fromCharCode(header[156] || 48);
    const rawSize = readTarString(header, 124, 12).trim();
    const size = Number.parseInt(rawSize || '0', 8);
    const start = offset + 512;
    const end = start + size;
    if (!Number.isSafeInteger(size) || size < 0 || end > tar.length) throw new Error('Nasiko archive is truncated.');
    const payload = tar.subarray(start, end);
    const isBinary = !prefix && name === expectedName && (type === '0' || type === '\0');
    const isAppleDouble = !prefix && name === `._${expectedName}` && type === '0' && size <= 1024 * 1024;
    const isPaxMetadata = !prefix && name === `PaxHeader/${expectedName}` && type === 'x' && size <= 64 * 1024
      && !/(?:^|\n)(?:path|linkpath)=/i.test(payload.toString('utf8'));

View on GitHub (pinned to 06c5e118c4)

Solutions

  1. Re-run the install to rule out transient corruption
  2. Manually fetch the layer and try `gunzip -t` on it to confirm the artifact itself is a valid gzip stream
  3. If the legitimate binary now exceeds 64 MiB, raise MAX_BINARY_BYTES deliberately after review
  4. Report reproducible corrupt-for-pinned-digest artifacts upstream
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await installNasiko({ version: 'v0.1.0' });
} catch (error) {
  if (/invalid or exceeds the decompressed size limit/.test(String(error.message))) {
    // Retry once for transient corruption; if reproducible, gunzip -t the
    // downloaded layer to decide between oversized binary (raise cap after
    // review) and corrupt artifact (report upstream).
  }
  throw error;
}

Prevention

When it happens

Trigger: The layer bytes are not a valid gzip stream, or gunzipping them produces more than 64 MiB + 2 KiB. Concretely: registry served non-gzip content for the pinned digest, the response was truncated mid-stream, or the archive intentionally expands past the binary size limit.

Common situations: Corrupted downloads on flaky networks; mirrors substituting content; upstream shipping a debug/unstripped binary larger than 64 MiB; crafted compression-bomb payloads.

Related errors


AI-assisted analysis of affaan-m/ECC@06c5e118c4 (2026-08-18). Data as JSON: /api/errors/d90e45a3a8941371. Report an issue: GitHub.