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
- Regenerate the archive with standard tooling (cpio -H newc / -H odc) which emits correct NUL padding
- Fix your writer to pad with 0x00 bytes to the format's alignment boundary
- Verify the alignment used matches the magic (newc=4, binary=2, odc=1)
- 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
- Pad with 0x00 bytes, never spaces, to the format's alignment (newc=4, binary=2, odc=1)
- Round-trip custom-written archives through the reader in CI
- Avoid in-place patching of archive bytes
- Verify checksums to detect corruption-induced non-NUL padding
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
- Invalid ARJ method-4 compressed data: non-zero trailing bits
- Invalid XZ BCJ filter 0x${filter.id.toString(16)} start offs
- CPIO member '${memberPath}' has an inconsistent declared siz
- CPIO member '${memberPath}' is truncated
- CPIO member '${memberPath}' has an invalid CRC checksum
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/1f904b22b6687b22.
Report an issue: GitHub.