can1357/oh-my-pi · error · ArchiveError
Invalid RPM package: truncated main header
Error message
Invalid RPM package: truncated main header
What it means
parseMainHeader validates that the RPM main header body it read is exactly intro.bodySize bytes (index entries plus data region declared in the header intro). A mismatch means the file is shorter than its own header claims, so the package is truncated or corrupt. The library refuses to parse a self-inconsistent header rather than return partial metadata.
Source
Thrown at packages/utils/src/ar/rpm.ts:146
throw new ArchiveError(`Invalid RPM package: tag ${tag} must contain one string`);
}
const start = indexSize + offset;
const limit = indexSize + dataSize;
let end = start;
while (end < limit && body[end] !== 0) end++;
if (end === limit) throw new ArchiveError(`Invalid RPM package: tag ${tag} string is not NUL-terminated`);
if (end - start > 4096) throw new ArchiveError(`Invalid RPM package: tag ${tag} string is too large`);
try {
return UTF8_FATAL_DECODER.decode(body.subarray(start, end));
} catch {
throw new ArchiveError(`Invalid RPM package: tag ${tag} is not valid UTF-8`);
}
}
function parseMainHeader(body: Uint8Array, intro: HeaderIntro): RpmMetadata {
validateHeaderBody(body, intro, "main");
const indexSize = intro.indexCount * RPM_INDEX_ENTRY_SIZE;
if (body.byteLength !== intro.bodySize) throw new ArchiveError("Invalid RPM package: truncated main header");
const metadata: RpmMetadata = {};
for (let index = 0; index < intro.indexCount; index++) {
const recordOffset = index * RPM_INDEX_ENTRY_SIZE;
const tag = readUInt32BE(body, recordOffset);
const type = readUInt32BE(body, recordOffset + 4);
const offset = readUInt32BE(body, recordOffset + 8);
const count = readUInt32BE(body, recordOffset + 12);
if (offset > intro.dataSize) throw new ArchiveError(`Invalid RPM package: tag ${tag} points outside header data`);
if (
tag !== RPM_TAG_NAME &&
tag !== RPM_TAG_VERSION &&
tag !== RPM_TAG_PAYLOAD_FORMAT &&
tag !== RPM_TAG_PAYLOAD_COMPRESSOR &&
tag !== RPM_TAG_PAYLOAD_FLAGS
) {
continue;
}
const value = readHeaderString(body, indexSize, intro.dataSize, offset, count, type, tag);View on GitHub (pinned to 9690622007)
Solutions
- Re-download or re-copy the RPM and verify its checksum against the repository/mirror digest.
- Check the file size: if it is smaller than the original package, the transfer was truncated; retry the download.
- Test the package with rpm -qp <file>.rpm or rpm2cpio to confirm it is corrupt outside this library.
- If the source is a build artifact, rebuild the package with rpmbuild to regenerate a valid header.
Example fix
// before: parsing a partially downloaded file directly
const entries = await readArchive(fetchedBuffer);
// after: verify integrity first
const expected = await fetchChecksumFromRepo(url);
if (await Bun.hash(buffer) !== expected) throw new Error('RPM truncated/corrupt; re-download'); Defensive patterns
Strategy: validation
Validate before calling
const stat = await Bun.file(path).size;
// header intro dataSize/indexCount live at offset 96+8..96+16; body must fit in file
// cheap pre-check: an RPM main header can't exceed the file itself
if (stat < 96 + 16) throw new Error(`RPM too small (${stat} bytes); likely truncated`); Type guard
function looksLikeCompleteRpm(size: number, introIndexCount: number, introDataSize: number): boolean {
return 96 + 16 + introIndexCount * 16 + introDataSize <= size;
} Try / catch
try {
const meta = await readRpm(path);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes('truncated main header')) {
throw new Error('RPM file is truncated — re-download and verify checksum');
}
throw err;
} Prevention
- Always verify download checksums before parsing RPMs.
- Compare local file size to the repository's content-length after downloads.
- Avoid resuming interrupted downloads into the final artifact without re-validation.
When it happens
Trigger: Calling the archive reader (readRpm/metadata path) on an RPM whose main header intro declares indexCount*16 + dataSize bytes that exceed the bytes actually available at the main header offset — i.e. the read body length !== intro.bodySize.
Common situations: Incomplete downloads (interrupted transfer of an .rpm), files copied/truncated by a failed upload or rsync cut short, a corrupted package on a mirror, or concatenation/rewriting tools that chopped the file.
Related errors
- Invalid RPM package: truncated signature header
- Invalid RPM package: truncated ${what}
- Invalid RPM package: truncated ${what} header
- Invalid RPM package: non-zero signature alignment padding
- Invalid tar octal value: ${value}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/e8f743f5901d55ca.
Report an issue: GitHub.