affaan-m/ECC · error · Error

Unsafe Nasiko archive: nonzero tar padding.

Error message

Unsafe Nasiko archive: nonzero tar padding.

What it means

Tar pads every file entry to a 512-byte boundary. extractQualifiedTarGzip requires that all padding bytes between the end of an entry's payload and its padded boundary be zero. Nonzero padding indicates a malformed or tampered archive, so it throws this error instead of processing it.

Solutions

  1. Obtain the archive from the official registry again rather than a modified copy.
  2. Verify the archive checksum against the published digest.
  3. Repack the source file with standard tar so padding is zero-filled.
  4. If this happens on every download, inspect any proxy/CDN that may be altering bytes.

Example fix

// before
const tar = fs.readFileSync(untrustedPath);
const bin = extractQualifiedTarGzip(tar);
// after
const tar = fs.readFileSync(untrustedPath);
if (sha256(tar) !== PUBLISHED_DIGEST) throw new Error('Refusing unverified archive.');
const bin = extractQualifiedTarGzip(tar);
Defensive patterns

Strategy: validation

Validate before calling

const digest = crypto.createHash('sha256').update(archiveBuffer).digest('hex'); if (digest !== publishedDigest) throw new Error('Archive digest mismatch.');

Try / catch

try { return extractQualifiedTarGzip(tar); } catch (err) { if (err.message.includes('nonzero tar padding')) throw new Error('Archive failed integrity validation; refusing to install.'); throw err; }

Prevention

When it happens

Trigger: Calling extractQualifiedTarGzip with an archive where any byte in the padding region between payload end and the next 512-byte boundary is nonzero.

Common situations: Hand-crafted or maliciously modified tarballs; archives produced by nonconforming packers that put hidden data in padding; bit-rot or corruption in a cached download.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/a89556bbf2ad9078. Report an issue: GitHub.

Appendix: source

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

        || !tar.subarray(offset + 512, terminatorEnd).every(byte => byte === 0)
        || !tar.subarray(terminatorEnd).every(byte => byte === 0)
      ) {
        throw new Error('Unsafe Nasiko archive: incomplete terminator or nonzero trailing data.');
      }
      terminated = true;
      break;
    }
    const name = readTarString(header, 0, 100);
    const prefix = readTarString(header, 345, 155);
    const type = String.fromCharCode(header[156] || 48);
    const size = readTarOctal(header, 124, 12);
    const start = offset + 512;
    const end = start + size;
    const paddedEnd = start + Math.ceil(size / 512) * 512;
    if (!Number.isSafeInteger(end) || paddedEnd > tar.length) throw new Error('Nasiko archive is truncated.');
    const payload = tar.subarray(start, end);
    if (!tar.subarray(end, paddedEnd).every(byte => byte === 0)) {
      throw new Error('Unsafe Nasiko archive: nonzero tar padding.');
    }
    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'));
    if (isBinary && !binary && size > 0 && size <= MAX_BINARY_BYTES) binary = Buffer.from(payload);
    else if (!isAppleDouble && !isPaxMetadata) throw new Error('Unsafe Nasiko archive: expected exactly one bounded regular binary file.');
    offset = paddedEnd;
  }
  if (!terminated) throw new Error('Unsafe Nasiko archive: missing complete tar terminator.');
  if (!binary) throw new Error('Unsafe Nasiko archive: expected exactly one bounded regular binary file.');
  return binary;
}

function fetchBytes(url, options = {}) {
  const parsed = new URL(url);
  if (parsed.origin !== REGISTRY_ORIGIN || parsed.protocol !== 'https:') return Promise.reject(new Error('Nasiko download origin is not allowed.'));
  const maxBytes = options.maxBytes || MAX_ARCHIVE_BYTES;

View on GitHub (pinned to 8321021c54)