can1357/oh-my-pi · error · ArchiveError

Invalid CPIO archive: non-zero ${what} padding

Error message

Invalid CPIO archive: non-zero ${what} padding

What it means

CPIO requires alignment padding after the header+name block and after each entry's file data (4-byte for newc, 2-byte for binary, 1-byte for odc). validateZeroPadding walks that padding region and throws ArchiveError if any byte is non-zero. Strict writers must pad with NUL bytes; non-zero padding signals corruption or a nonconforming writer.

Source

Thrown at packages/utils/src/ar/cpio.ts:198

			mtime: parseDigits(bytes, offset + 48, 11, 8, "modification time"),
			nameSize: field6(59, "name size"),
			fileSize: parseDigits(bytes, offset + 65, 11, 8, "file size"),
		};
	}
	throw new ArchiveError(`Invalid CPIO archive: unsupported or corrupt magic at offset ${offset}`);
}

function decodeUtf8(bytes: Uint8Array): string | undefined {
	try {
		return UTF8_FATAL_DECODER.decode(bytes);
	} catch {
		return undefined;
	}
}

function validateZeroPadding(bytes: Uint8Array, start: number, end: number, what: string): void {
	for (let offset = start; offset < end; offset++) {
		if (bytes[offset] !== 0) throw new ArchiveError(`Invalid CPIO archive: non-zero ${what} padding`);
	}
}

function makeLinkTarget(recordPath: string, targetBytes: Uint8Array, maxPathBytes: number): LinkTarget {
	assertArchivePathBytes(targetBytes.byteLength, "link target", maxPathBytes);
	const rawTarget = decodeUtf8(targetBytes);
	if (rawTarget === undefined || rawTarget.includes("\0")) {
		throw new ArchiveError(`Invalid CPIO archive: symlink '${recordPath}' has an invalid UTF-8 target`);
	}
	const portableTarget = rawTarget.replace(/\\/g, "/");
	if (path.posix.isAbsolute(portableTarget)) return { path: portableTarget, resolveTarget: false };
	const normalized = normalizeArchiveLookupPath(path.posix.join(path.posix.dirname(recordPath), portableTarget));
	return normalized === undefined
		? { path: portableTarget, resolveTarget: false }
		: { path: normalized, resolveTarget: true };
}

/** Parse an already-materialized CPIO stream for direct and RPM-composed readers. */

View on GitHub (pinned to 9690622007)

Solutions

  1. Regenerate the archive with standard tooling (cpio -H newc / -H odc) which emits correct NUL padding
  2. Fix your writer to pad with 0x00 bytes to the format's alignment boundary
  3. Verify the alignment used matches the magic (newc=4, binary=2, odc=1)
  4. Scan the archive for non-NUL bytes in padding regions to locate the corruption

Example fix

// before: writer pads with spaces
const pad = ' '.repeat(align - (len % align));
// after: pad with NUL bytes
const pad = '\0'.repeat((align - (len % align)) % align);
Defensive patterns

Strategy: validation

Validate before calling

// after parsing succeeds, archives are verified internally; pre-validate writers in CI:
const entries = readCpioEntriesFromBuffer(testArchiveBytes, options); // run round-trip in tests to catch bad padding

Try / catch

try {
  const entries = await readCpio(source, options);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes('non-zero') && err.message.includes('padding')) {
    // repack archive with standard tooling or fix writer padding
  } else throw err;
}

Prevention

When it happens

Trigger: Parsing an archive where name/data alignment padding contains garbage — typically because a writer padded with spaces (0x20), or the computed alignment/offsets shifted so real data or the next header is being read as padding. Raised from readCpioEntriesFromBuffer via validateZeroPadding on 'name' and 'data' regions.

Common situations: Hand-rolled archive writers using space padding; corruption flipping NUL bytes; writers using wrong alignment for the declared format (e.g. 4-byte data for odc which needs none); archives patched in place.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/1f904b22b6687b22. Report an issue: GitHub.