can1357/oh-my-pi · error · ArchiveError
${error instanceof Error ? error.message : String(error)}
Error message
${error instanceof Error ? error.message : String(error)} What it means
readExact wraps source.read in try/catch: if the read fails with anything that is not already an ArchiveError (network failure, permission error, decode error, etc.), the original message is re-wrapped in ArchiveError so all archive-reading failures share one error type. The message text is the underlying error's message.
Source
Thrown at packages/utils/src/ar/unix-ar.ts:247
records.push({ name, nameByteLength, dataOffset, size, mtimeSeconds: header.mtimeSeconds, mode: header.mode });
assertEntryCount(records.length, options.limits);
position = payloadEnd + (header.physicalSize & 1);
if (position > bytes.byteLength) throw new ArchiveError("Invalid ar archive: missing alignment byte");
}
return materializeEntries(records, longNames, memoryByteSource(bytes), options);
}
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 ar archive: truncated ${what}`);
}
try {
const bytes = await source.read(start, end);
if (bytes.byteLength !== end - start) throw new ArchiveError(`Invalid ar archive: truncated ${what}`);
return bytes;
} catch (error) {
if (error instanceof ArchiveError) throw error;
throw new ArchiveError(error instanceof Error ? error.message : String(error));
}
}
async function readUnixArImpl(source: ByteSource, options: FormatReadOptions): Promise<ArchiveIndexEntry[]> {
if (!Number.isSafeInteger(source.size) || source.size < SIGNATURE.length)
throw new ArchiveError("Invalid ar archive signature");
readSignatureFromBuffer(await readExact(source, 0, SIGNATURE.length, "signature"));
const records: RawArMember[] = [];
let longNames: Uint8Array | undefined;
let metadataSize = 0;
for (let position = SIGNATURE.length; position < source.size; ) {
const headerBytes = await readExact(source, position, position + HEADER_SIZE, "member header");
const header = parseHeader(headerBytes);
metadataSize += HEADER_SIZE;
assertIndexSize(metadataSize, options.limits, "index");
const payloadOffset = position + HEADER_SIZE;
const payloadEnd = payloadOffset + header.physicalSize;
if (!Number.isSafeInteger(payloadEnd) || payloadEnd > source.size) {View on GitHub (pinned to 9690622007)
Solutions
- Read the wrapped message — it is the original cause; fix that underlying problem.
- Check file permissions / re-authenticate before parsing remote archives.
- Test your custom ByteSource: read(start,end) must return a Uint8Array of exactly end-start bytes.
- Catch ArchiveError uniformly and inspect message/cause instead of handling raw source errors.
Example fix
// before: wrong custom source
read(start, end) { return this.buf.slice(start, end); } // may be short/throw
// after
async read(start: number, end: number): Promise<Uint8Array> {
if (end > this.size) throw new ArchiveError(`range past EOF`);
return this.buf.subarray(start, end);
} Defensive patterns
Strategy: try-catch
Type guard
function isArchiveError(err: unknown): err is ArchiveError {
return err instanceof ArchiveError;
} Try / catch
try {
return await readUnixAr(source);
} catch (err) {
if (isArchiveError(err)) {
logger.error('ar parse failed', { message: err.message }); // message = root cause
throw new UserFacingError(`could not read archive: ${err.message}`);
}
throw err;
} Prevention
- Check permissions/auth on the byte source before parsing (EACCES and 401s surface through this wrap).
- Keep the underlying error message in logs — it is the real cause.
- Type-test custom ByteSource implementations (correct read signature, no lost `this`).
- Do not swallow non-ArchiveError throws from your own source.read; fix them at the source.
When it happens
Trigger: source.read(start,end) throws — e.g. EACCES on the file, an HTTP 4xx/5xx from a range request, an abort, or a TypeError from a bad custom ByteSource implementation.
Common situations: Permission errors on protected files; expired auth tokens for remote sources; misimplemented ByteSource (read signature mismatch, wrong this-binding); transient network drops.
Related errors
- Failed to read ASAR member '${formatArchivePathForError(memb
- Unable to read ARJ archive: ${error instanceof Error ? error
- Invalid ARJ archive: truncated data
- ASAR member '${formatArchivePathForError(memberPath)}' is tr
- Unable to read CAB archive: ${error instanceof Error ? error
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/bbe9f92d24eb92b7.
Report an issue: GitHub.