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
- Re-run the install to rule out transient corruption
- Manually fetch the layer and try `gunzip -t` on it to confirm the artifact itself is a valid gzip stream
- If the legitimate binary now exceeds 64 MiB, raise MAX_BINARY_BYTES deliberately after review
- 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
- Keep released binaries under the 64 MiB cap (strip debug symbols before packaging)
- Test `gunzip -t` on the produced layer in the release pipeline
- Do not raise maxOutputLength casually - the cap is the decompression-bomb guard
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.