can1357/oh-my-pi · error · ArchiveError

Invalid CPIO archive: mode exceeds 16 bits

Error message

Invalid CPIO archive: mode exceeds 16 bits

What it means

readCpioEntriesFromBuffer validates each parsed header's mode against the 16-bit POSIX file-mode space and throws ArchiveError if mode > 0xFFFF. Old-binary headers read mode as a 16-bit value (cannot exceed), so in practice this fires on ASCII formats where a corrupt or hostile 8-hex-digit field encodes a value beyond 0xFFFF — indicating a corrupt header or tampered archive.

Source

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

	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. */
export function readCpioEntriesFromBuffer(bytes: Uint8Array, options: FormatReadOptions): ArchiveIndexEntry[] {
	assertInMemorySize(bytes.byteLength, options.limits);
	const records: ParsedRecord[] = [];
	let offset = 0;
	let metadataSize = 0;
	let foundTrailer = false;

	while (offset < bytes.byteLength) {
		const header = parseHeader(bytes, offset);
		if (header.mode > 0xffff) throw new ArchiveError("Invalid CPIO archive: mode exceeds 16 bits");
		if (header.nameSize < 1) throw new ArchiveError("Invalid CPIO archive: name size must include a NUL terminator");
		assertArchivePathBytes(header.nameSize - 1, "member path", options.limits.maxPathBytes);
		assertArchiveMemberSize(header.fileSize, "(CPIO entry)", options.limits);

		const nameStart = offset + header.headerSize;
		const nameEnd = nameStart + header.nameSize;
		const dataOffset = align(nameEnd, header.alignment);
		const dataEnd = dataOffset + header.fileSize;
		const nextOffset = align(dataEnd, header.alignment);
		requireRange(bytes, nameStart, nameEnd, "member name");
		requireRange(bytes, dataOffset, dataEnd, "member data");
		requireRange(bytes, dataEnd, nextOffset, "member padding");
		if (bytes[nameEnd - 1] !== 0) throw new ArchiveError("Invalid CPIO archive: member name is not NUL-terminated");
		for (let index = nameStart; index < nameEnd - 1; index++) {
			if (bytes[index] === 0) throw new ArchiveError("Invalid CPIO archive: member name contains an embedded NUL");
		}
		validateZeroPadding(bytes, nameEnd, dataOffset, "name");
		validateZeroPadding(bytes, dataEnd, nextOffset, "data");

View on GitHub (pinned to 9690622007)

Solutions

  1. Rebuild the archive with a standard tool so mode fields contain conventional 16-bit permission/type values
  2. Fix a custom writer to mask mode to 0o7777 | file-type bits (e.g. mode & 0o1707777 → but emit ≤ 0xFFFF)
  3. Verify archive integrity (checksum) — this error usually means the mode field bytes are corrupt
  4. Treat untrusted archives triggering this as rejected input in your ingestion pipeline

Example fix

// before: writer emits 32-bit mode
header.write(mode.toString(16).padStart(8, '0'), MODE_OFFSET, 'ascii');
// after: clamp to 16-bit st_mode space
const m16 = mode & 0xffff;
header.write(m16.toString(16).padStart(8, '0'), MODE_OFFSET, 'ascii');
Defensive patterns

Strategy: try-catch

Try / catch

try {
  const entries = await readCpio(source, options);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes('mode exceeds 16 bits')) {
    // corrupt/hostile header: reject the archive rather than retry
  } else throw err;
}

Prevention

When it happens

Trigger: Parsing a newc ('070701'/'070702') archive whose mode field hex value exceeds FFFF, e.g. all-'F' fields or corruption shifting digit bytes into the mode slot; crafted archives from fuzzing/security tooling.

Common situations: Fuzzed or maliciously crafted archives; byte corruption in transit; custom writers emitting 32-bit mode words (including high flags) into the mode field instead of the standard permission+type bits.

Related errors


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