can1357/oh-my-pi · error · ArchiveError
Invalid RPM package: truncated ${what}
Error message
Invalid RPM package: truncated ${what} What it means
ArchiveError thrown by the RPM reader's readExact() helper when the requested byte range [start,end) is not a valid range within the source (non-safe integers, negative start, end<start, or end beyond source.size). This is the first of two truncation checks — it validates the range arithmetically before any I/O.
Source
Thrown at packages/utils/src/ar/rpm.ts:48
totalSize: number;
}
interface RpmMetadata {
name?: string;
version?: string;
payloadFormat?: string;
payloadCompressor?: string;
payloadFlags?: string;
}
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;View on GitHub (pinned to 9690622007)
Solutions
- Re-download or re-fetch the .rpm file and verify size/checksum against the repository metadata
- Check that the byte source (file/blob) is fully written before parsing
- Confirm the file actually is an RPM (starts with the ar '!<arch>' / RPM lead) before parsing
Example fix
// before
const rpm = await readRpmArchive(await Bun.file(partialPath).arrayBuffer());
// after
const buf = await Bun.file(path).arrayBuffer();
if (buf.byteLength < 96) throw new Error(`RPM too small: ${buf.byteLength} bytes`);
const rpm = await readRpmArchive(buf); Defensive patterns
Strategy: validation
Validate before calling
const size = Bun.file(path).size;
if (size < 96) throw new Error(`rpm too small (${size} bytes)`); // minimum: lead + headers Type guard
null
Try / catch
try {
const rpm = await readRpmArchive(buf);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes('truncated')) {
// surface 'download incomplete' to the user
} else throw err;
} Prevention
- Verify downloaded file size against repository metadata before parsing
- Buffer the whole source before parsing instead of streaming partial data
- Confirm the file extension/lead actually indicate an RPM
When it happens
Trigger: Reading RPM structures (initial lead, signature header, main intro, body, payload) where computed offsets exceed the actual file size — i.e. the file is smaller than the RPM format requires at that point.
Common situations: Truncated downloads of .rpm files, HTTP transfers cut short, passing a non-RPM or empty file to the RPM reader, or CDN/proxy stripping bytes.
Related errors
- Invalid RPM package: truncated ${what} header
- Invalid RPM package: truncated main header
- Invalid RPM package: truncated signature header
- ASAR member '${formatArchivePathForError(memberPath)}' is tr
- Invalid CAB archive: declared cabinet size is out of bounds
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/fc2aad90a8cf4d5f.
Report an issue: GitHub.