can1357/oh-my-pi · error · ArchiveError

Failed to read tar archive

Error message

Failed to read tar archive

What it means

readTar reads the entire archive source into memory before parsing. If readAllBytes throws a non-ArchiveError (stream I/O failure, decode error, etc.), it is wrapped in this generic ArchiveError so callers only need to catch one type. The underlying cause message is preserved when the original error is an Error instance.

Source

Thrown at packages/utils/src/ar/tar.ts:586

			mtimeMs,
			mode,
			storage: { type: "member", source: new TarMemberSource(buffer, dataOffset, sparse) },
		});
	}
	if (!sawTerminator) throw new ArchiveError("Not a valid tar archive: missing terminating zero block");
	resolvePendingLinks(entries, pendingLinks, limits);
	return [...entries.values()];
}

/** Read and index a tar source after one bounded whole-stream read. */
export const readTar: FormatReader = async (source, options) => {
	assertInMemorySize(source.size, options.limits);
	let bytes: Uint8Array;
	try {
		bytes = await readAllBytes(source);
	} catch (error) {
		if (error instanceof ArchiveError) throw error;
		throw new ArchiveError(error instanceof Error ? error.message : "Failed to read tar archive");
	}
	if (bytes.byteLength !== source.size) throw new ArchiveError("Invalid archive: truncated data");
	return readTarEntriesFromBuffer(bytes, options);
};

/** Detect a tar header, including legacy pre-ustar archives, by its checksum. */
export function sniffTar(bytes: Uint8Array): boolean {
	if (bytes.byteLength < BLOCK_SIZE) return false;
	if (isZeroBlock(bytes, 0)) return true;
	try {
		if (readTarString(bytes, NAME_OFFSET, NAME_LENGTH).length === 0) return false;
		const size = readTarSize(bytes, SIZE_OFFSET);
		return Number.isSafeInteger(paddedSize(size)) && checksumMatches(bytes, 0);
	} catch {
		return false;
	}
}

View on GitHub (pinned to 9690622007)

Solutions

  1. Inspect the wrapped message (or the original console/log) for the real I/O cause and fix that first
  2. Verify the file/source is readable and unchanged before calling readTar
  3. Re-download or re-open the archive; retry only if the cause was transient (network)
  4. If you supply a custom source, ensure its read/byte-returning contract never rejects except on real failures

Example fix

// before: source may be a dying stream
await readTar({ stream: resp.body, ... });
// after: buffer to a stable file first, then read
await Bun.write(tmp, resp);
await readTar({ size: tmp.size, bytes: await Bun.file(tmp).bytes(), ... });
Defensive patterns

Strategy: try-catch

Validate before calling

const stat = await fs.stat(path);
if (!stat.isFile()) throw new Error("not a readable regular file");

Type guard

function isArchiveError(err: unknown): err is ArchiveError {
  return err instanceof ArchiveError;
}

Try / catch

try {
  return await readTar(source, options);
} catch (err) {
  if (err instanceof ArchiveError && err.message === "Failed to read tar archive") {
    // underlying I/O failed: check disk, permissions, or stream state
  }
  throw err;
}

Prevention

When it happens

Trigger: Passing a source whose underlying stream/socket/file fails during readAllBytes — closed file descriptor, EACCES on an opened-but-revoked file, network stream reset mid-read, or a source reader that throws a non-Archive error.

Common situations: Reading a tar from an HTTP response whose connection dropped, reading from a file deleted or permission-revoked between open and read, custom source implementations whose read() rejects, disk I/O errors.

Related errors


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