can1357/oh-my-pi · error · ArchiveError

Invalid RPM package: truncated signature header

Error message

Invalid RPM package: truncated signature header

What it means

After the lead, the reader loads the signature header body and requires at least signatureIntro.bodySize bytes of it to be present. Fewer bytes than the signature header declares means the file ends early — the signature region is truncated — so parsing is aborted before reading the main header.

Source

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

	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);
	const signatureBodyAndPadding = await readExact(
		source,
		RPM_LEAD_SIZE + RPM_HEADER_INTRO_SIZE,
		mainHeaderOffset,
		"signature header",
	);
	if (signatureBodyAndPadding.byteLength < signatureIntro.bodySize) {
		throw new ArchiveError("Invalid RPM package: truncated signature header");
	}
	validateHeaderBody(signatureBodyAndPadding.subarray(0, signatureIntro.bodySize), signatureIntro, "signature");
	for (let offset = signatureIntro.bodySize; offset < signatureBodyAndPadding.byteLength; offset++) {
		if (signatureBodyAndPadding[offset] !== 0) {
			throw new ArchiveError("Invalid RPM package: non-zero signature alignment padding");
		}
	}

	const mainIntroBytes = await readExact(
		source,
		mainHeaderOffset,
		mainHeaderOffset + RPM_HEADER_INTRO_SIZE,
		"main header intro",
	);
	const mainIntro = parseHeaderIntro(mainIntroBytes, options, "main");
	assertIndexSize(signatureIntro.totalSize + mainIntro.totalSize, options.limits, "RPM headers");
	const mainBodyOffset = mainHeaderOffset + RPM_HEADER_INTRO_SIZE;
	const mainBody = await readExact(source, mainBodyOffset, mainBodyOffset + mainIntro.bodySize, "main header");

View on GitHub (pinned to 9690622007)

Solutions

  1. Re-download the RPM and verify its checksum against the repository digest.
  2. Compare the local file size against the mirror's content-length; a smaller size confirms truncation.
  3. Check for proxy/transfer limits (reverse proxies, S3 multipart aborts) that cut the download short and retry.
  4. Validate with rpm -qp <file>; if the system rpm also rejects it, the file is definitively corrupt.

Example fix

// before: trusting a partially streamed file
await Bun.write(dest, await resp.arrayBuffer()); // may silently truncate on abort
// after: verify completeness
const expected = Number(resp.headers.get('content-length'));
const buf = await resp.arrayBuffer();
if (buf.byteLength !== expected) throw new Error('download truncated');
await Bun.write(dest, buf);
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the file is at least large enough for lead + signature header before parsing
const size = await Bun.file(path).size;
if (size < 96 + 16) throw new Error(`RPM ${path} too small (${size}B) — truncated download`);

Try / catch

try {
  return await readRpm(path);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes('truncated signature header')) {
    throw new Error('RPM truncated mid-signature-header; re-download and verify checksum');
  }
  throw err;
}

Prevention

When it happens

Trigger: readExact succeeded on lead+intro but the subsequent read of the signature header returned fewer bytes than the signature intro's declared bodySize (indexCount*16 + dataSize); raised before validateHeaderBody.

Common situations: Truncated downloads/uploads, files clipped by transfer size limits, storage corruption near the end of the file, or streams that were closed before the whole package was written.

Related errors


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