affaan-m/ECC · error · Error
Unsafe Nasiko archive: invalid tar size field.
Error message
Unsafe Nasiko archive: invalid tar size field.
What it means
readTarOctal parses a tar header size field, which must be space-padded octal digits. This error (thrown at the regex check) means the field does not match the expected tar numeric format, so the archive header is corrupt or not a real tar header. It is part of the library's defensive extraction of the gzip artifact.
Solutions
- Gunzip the archive manually and hexdump the first 512 bytes to confirm it is a real tar header with an octal size at offset 124.
- Re-download the artifact — corruption mid-transfer is the most common cause.
- If the producer uses GNU base-256 size encoding, repack with `tar --format=ustar` so sizes stay ASCII octal.
- Verify you are not accidentally passing the gzip bytes where tar bytes are expected (double-gunzip).
Example fix
// before
// extractQualifiedTarGzip(artifact) -> invalid tar size field
// after
const tar = zlib.gunzipSync(fs.readFileSync('artifact.gz'));
console.log(tar.subarray(0, 512).toString('hex').slice(0, 200)); // inspect header
// repack if needed:
// tar --format=ustar -cf artifact.tar bin/ && gzip artifact.tar Defensive patterns
Strategy: validation
Validate before calling
const tar = zlib.gunzipSync(archiveBytes);
if (tar.length % 512 !== 0) throw new Error('tar length not block-aligned');
const sizeField = tar.subarray(124, 136).toString('ascii');
if (!/^ *([0-7]+)[ \0]*$/.test(sizeField)) throw new Error('first header not a ustar tar header'); Type guard
const isUstarHeader = (tar) => /^ *([0-7]+)[ \0]*$/.test(tar.subarray(124, 136).toString('ascii')); Try / catch
try { installNasiko(opts); } catch (e) { if (e.message.includes('invalid tar size field')) console.error('archive is not a plain ustar tar; repack with --format=ustar'); throw e; } Prevention
- Publish artifacts packed with --format=ustar to keep numeric fields ASCII octal.
- Verify artifact digest before extraction to rule out corruption.
- Spot-check the first 512 bytes of new artifacts in CI.
When it happens
Trigger: extractQualifiedTarGzip walks 512-byte tar blocks and calls readTarOctal on a header whose size field contains non-octal bytes — e.g. the gunzipped data is not a tar at all, the header offset drifted, or the file uses a non-standard numeric format (base-256 GNU extension the regex rejects).
Common situations: Extracting an artifact that is gzip but not tar (bare binary gzipped), a corrupted download, or a GNU/sparse tar feature that encodes size in base-256 binary instead of ASCII octal.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Nasiko archive is truncated.
- Unsafe Nasiko archive: expected exactly one bounded regular…
- Unsafe Nasiko archive: incomplete terminator or nonzero…
- Unsafe Nasiko archive: missing complete tar terminator.
- Unsafe Nasiko archive: nonzero tar padding.
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/ecc89fe56c9fab02.
Report an issue: GitHub.
Appendix: 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 readTarOctal(block, offset, length) {
const field = block.subarray(offset, offset + length).toString('ascii');
const match = /^ *([0-7]+)[ \0]*$/.exec(field);
if (!match) throw new Error('Unsafe Nasiko archive: invalid tar size field.');
const size = Number.parseInt(match[1], 8);
if (!Number.isSafeInteger(size) || size < 0) {
throw new Error('Unsafe Nasiko archive: invalid tar size field.');
}
return size;
}
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;
let terminated = false;
while (offset < tar.length) {
if (offset + 512 > tar.length) throw new Error('Unsafe Nasiko archive: truncated tar header.');
const header = tar.subarray(offset, offset + 512);
if (header.every(byte => byte === 0)) {View on GitHub (pinned to 8321021c54)