can1357/oh-my-pi · error · ArchiveError

Invalid RPM package: corrupt ${what} header magic

Error message

Invalid RPM package: corrupt ${what} header magic

What it means

ArchiveError thrown by parseHeaderIntro() when an RPM header intro (signature or main) fails validation: the intro is not exactly RPM_HEADER_INTRO_SIZE bytes or its first 4 bytes are not the RPM header magic (0x8eade801). Indicates the byte stream is not where an RPM header should be.

Source

Thrown at packages/utils/src/ar/rpm.ts:57

}

function align(value: number, alignment: number): number {
	const remainder = value % alignment;
	return remainder === 0 ? value : value + alignment - remainder;
}

async function readExact(source: ByteSource, start: number, end: number, what: string): Promise<Uint8Array> {
	if (!Number.isSafeInteger(start) || !Number.isSafeInteger(end) || start < 0 || end < start || end > source.size) {
		throw new ArchiveError(`Invalid RPM package: truncated ${what}`);
	}
	const bytes = await source.read(start, end);
	if (bytes.byteLength !== end - start) throw new ArchiveError(`Invalid RPM package: truncated ${what}`);
	return bytes;
}

function parseHeaderIntro(bytes: Uint8Array, options: FormatReadOptions, what: string): HeaderIntro {
	if (bytes.byteLength !== RPM_HEADER_INTRO_SIZE || readUInt32BE(bytes, 0) !== RPM_HEADER_MAGIC) {
		throw new ArchiveError(`Invalid RPM package: corrupt ${what} header magic`);
	}
	for (let offset = 4; offset < 8; offset++) {
		if (bytes[offset] !== 0) throw new ArchiveError(`Invalid RPM package: corrupt ${what} header reserved bytes`);
	}
	const indexCount = readUInt32BE(bytes, 8);
	const dataSize = readUInt32BE(bytes, 12);
	assertEntryCount(indexCount, options.limits);
	const indexSize = indexCount * RPM_INDEX_ENTRY_SIZE;
	const bodySize = indexSize + dataSize;
	if (!Number.isSafeInteger(bodySize)) throw new ArchiveError(`Invalid RPM package: ${what} header is too large`);
	assertIndexSize(RPM_HEADER_INTRO_SIZE + bodySize, options.limits, `RPM ${what} header`);
	return { indexCount, dataSize, bodySize, totalSize: RPM_HEADER_INTRO_SIZE + bodySize };
}

function validateHeaderBody(body: Uint8Array, intro: HeaderIntro, what: string): void {
	const indexSize = intro.indexCount * RPM_INDEX_ENTRY_SIZE;
	if (body.byteLength !== intro.bodySize) throw new ArchiveError(`Invalid RPM package: truncated ${what} header`);
	for (let index = 0; index < intro.indexCount; index++) {

View on GitHub (pinned to 9690622007)

Solutions

  1. Verify the file is a genuine .rpm (check the RPM lead magic first)
  2. Re-download the package
  3. Check for leading bytes/offset drift if you wrapped the source (e.g. skipped the lead incorrectly)

Example fix

// before
await readRpmArchive(buffer.subarray(claimedOffset));
// after
// pass the full, unshifted buffer — the reader computes the lead/header offsets itself
await readRpmArchive(buffer);
Defensive patterns

Strategy: validation

Validate before calling

const lead = new Uint8Array(buf, 0, 4);
const isRpm = lead[0] === 0xed && lead[1] === 0xab && lead[2] === 0xee && lead[3] === 0xdb;
if (!isRpm) throw new Error('not an RPM package');

Type guard

function isRpmBuffer(buf: Uint8Array): boolean {
  return buf.byteLength >= 4 && buf[0] === 0xed && buf[1] === 0xab && buf[2] === 0xee && buf[3] === 0xdb;
}

Try / catch

try {
  const rpm = await readRpmArchive(buf);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes('header magic')) {
    // report 'file is not a valid RPM' to the caller
  } else throw err;
}

Prevention

When it happens

Trigger: Parsing the signature or main header intro whose bytes don't begin with the RPM header magic — wrong offset computed from the lead, file is not an RPM, or the header region is corrupted/overwritten.

Common situations: Non-RPM files renamed to .rpm, corrupted downloads, misaligned leads from hand-crafted or exotic packages (e.g. unusual padding).

Related errors


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