can1357/oh-my-pi · error · ArchiveError

Invalid RPM package: bad lead magic

Error message

Invalid RPM package: bad lead magic

What it means

readRpmArchive reads the first 96-byte RPM lead plus header intro and checks the lead magic (0xEDABEEDB via sniffRpm). If the bytes do not match, the file is not an RPM package at all, so the reader fails fast before any parsing.

Source

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

			return xzDecompress(payload, maxOutput);
		case "zstd":
		case "zstdio":
			return zstdDecompress(payload, maxOutput);
		case "lzma":
			if (!sniffLzmaAlone(payload)) throw new ArchiveError(`RPM package '${identity}' has a malformed LZMA payload`);
			return lzmaAloneDecompress(payload, maxOutput);
		case "none":
			if (!sniffCpio(payload))
				throw new ArchiveError(`RPM package '${identity}' has an invalid uncompressed CPIO payload`);
			return payload;
		default:
			throw new ArchiveError(`RPM package '${identity}' uses unsupported payload compressor '${method}'`);
	}
}

async function readRpmArchive(source: ByteSource, options: FormatReadOptions): Promise<ArchiveIndexEntry[]> {
	const initial = await readExact(source, 0, RPM_LEAD_SIZE + RPM_HEADER_INTRO_SIZE, "lead and signature header");
	if (!sniffRpm(initial)) throw new ArchiveError("Invalid RPM package: bad lead magic");
	const major = initial[4]!;
	const packageType = (initial[6]! << 8) | initial[7]!;
	if (major < 3 || packageType > 1) throw new ArchiveError("Unsupported RPM package lead version or type");
	const signatureType = (initial[78]! << 8) | initial[79]!;
	if (signatureType !== RPM_SIGNATURE_TYPE_HEADER) {
		throw new ArchiveError(`Unsupported RPM signature type ${signatureType}; only header signatures are supported`);
	}
	const leadNameEnd = initial.subarray(10, 76).indexOf(0);
	const leadNameBytes = initial.subarray(10, leadNameEnd < 0 ? 76 : 10 + leadNameEnd);
	let leadName = "unknown package";
	try {
		const decoded = new TextDecoder("utf-8", { fatal: true }).decode(leadNameBytes);
		if (decoded) leadName = decoded;
	} catch {}

	const signatureIntro = parseHeaderIntro(initial.subarray(RPM_LEAD_SIZE), options, "signature");
	const signatureEnd = RPM_LEAD_SIZE + signatureIntro.totalSize;
	const mainHeaderOffset = align(signatureEnd, 8);

View on GitHub (pinned to 9690622007)

Solutions

  1. Verify the file path/URL actually points to an RPM; check the first bytes with `file <path>` — it should report 'RPM v3/v4'.
  2. Inspect the start of the response: if it's HTML, fix the download URL (mirror 404/redirect) and re-download.
  3. Ensure you are using the RPM reader and not passing a .deb/.tar.gz to it; route each file to the right format reader.
  4. Checksum-verify the download to confirm you got the real package.

Example fix

// before
const entries = await readRpm(maybeRpmPath);
// after: sniff before parsing
const head = new Uint8Array(await Bun.file(path).slice(0, 4).arrayBuffer());
if (!(head[0] === 0xed && head[1] === 0xab && head[2] === 0xee && head[3] === 0xdb)) throw new Error('not an RPM file');
Defensive patterns

Strategy: validation

Validate before calling

export async function isRpmFile(path: string): Promise<boolean> {
  const b = new Uint8Array(await Bun.file(path).slice(0, 4).arrayBuffer());
  return b[0] === 0xed && b[1] === 0xab && b[2] === 0xee && b[3] === 0xdb;
}
// call before readRpm

Type guard

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

Try / catch

try {
  return await readRpm(path);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes('bad lead magic')) {
    throw new Error(`${path} is not an RPM file (bad magic); check path/download`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling the RPM reader (readRpm/metadata) on a file whose first four bytes are not the RPM lead magic — e.g. a .deb, a tarball, an HTML error page saved as .rpm, or an empty/zero-byte file path.

Common situations: Pointing the reader at the wrong file (deb vs rpm), downloading a mirror's 404 page instead of the package, passing a source RPM stream that was already partially consumed, or a URL redirect to a login page.

Related errors


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