can1357/oh-my-pi · error · Error
Invalid EPUB: missing content.opf
Error message
Invalid EPUB: missing content.opf
What it means
The converter resolved an opf path from container.xml but archiveEntryText found no entry at that path inside the ZIP. This means the package document (content.opf) referenced by the container is absent, so metadata and spine cannot be read and convert() aborts.
Source
Thrown at packages/coding-agent/src/markit/converters/epub.ts:72
async convert(input: Buffer, _streamInfo: StreamInfo): Promise<ConversionResult> {
const entries = await readArchiveEntries({ bytes: input, format: "zip" });
const parser = new XMLParser({
ignoreAttributes: false,
attributeNamePrefix: "@_",
textNodeName: "#text",
processEntities: { maxTotalExpansions: 1_000_000 },
});
// Find content.opf path from container.xml
const containerXml = archiveEntryText(entries, "META-INF/container.xml");
if (!containerXml) throw new Error("Invalid EPUB: missing container.xml");
const container = parser.parse(containerXml) as ContainerDoc;
const rootfile = container.container?.rootfiles?.rootfile;
const opfPath = Array.isArray(rootfile) ? rootfile[0]["@_full-path"] : rootfile?.["@_full-path"];
if (!opfPath) throw new Error("Invalid EPUB: missing rootfile path");
// Parse content.opf
const opfXml = archiveEntryText(entries, opfPath);
if (!opfXml) throw new Error("Invalid EPUB: missing content.opf");
const opf = parser.parse(opfXml) as OpfDoc;
// Extract metadata
const meta: Metadata = opf.package?.metadata ?? {};
const metadata: Record<string, string | undefined> = {
title: this.getText(meta["dc:title"]),
authors: this.getTextArray(meta["dc:creator"]).join(", ") || undefined,
language: this.getText(meta["dc:language"]),
publisher: this.getText(meta["dc:publisher"]),
date: this.getText(meta["dc:date"]),
description: this.getText(meta["dc:description"]),
};
// Build manifest map (id → href)
const manifestItems = opf.package?.manifest?.item;
const itemList = Array.isArray(manifestItems) ? manifestItems : manifestItems ? [manifestItems] : [];
const manifest = new Map<string, string>();
for (const item of itemList) {
manifest.set(item["@_id"], item["@_href"]);
}View on GitHub (pinned to 9690622007)
Solutions
- Compare the full-path in META-INF/container.xml against actual entry names (unzip -l); fix the path or rename the entry to match exactly (case-sensitive).
- Rebuild the EPUB with a compliant packer (epubcheck-validated).
- Re-download the EPUB; the archive is likely corrupt or partially transferred.
- If repacking manually, include the OPF at the exact path the container references.
Example fix
// before (container.xml says OEBPS/content.opf, archive has OEBPS/Content.opf) // after: rename entry to match zip book.epub OEBPS/content.opf # exact case as full-path
Defensive patterns
Strategy: validation
Validate before calling
async function opfEntryExists(path: string, listEntries: (p: string) => Promise<string[]>, readEntry: (p: string, name: string) => Promise<string>): Promise<boolean> {
const containerXml = await readEntry(path, "META-INF/container.xml");
const full = /full-path="([^"]+)"/.exec(containerXml ?? "")?.[1];
if (!full) return false;
return (await listEntries(path)).includes(full);
} Try / catch
try {
const result = await markit.convertFile("book.epub");
} catch (err) {
if (err instanceof Error && err.message === "Invalid EPUB: missing content.opf") {
throw new Error("book.epub references an OPF that is absent from the archive; fix full-path or repack");
}
throw err;
} Prevention
- Match container.xml full-path against actual zip entries (case-sensitive) before conversion.
- Repack with EPUB-compliant tools so referenced parts are always included.
- Validate with epubcheck after any archive modification.
- Avoid filesystem case-mangling when moving EPUBs between OSes.
When it happens
Trigger: container.xml's rootfile full-path names a file (e.g. OEBPS/content.opf) that does not exist in the archive — wrong path, case mismatch, or the OPF was deleted.
Common situations: EPUB re-zipped across case-sensitive/insensitive filesystems (Content.opf vs content.opf); partial extraction/repack dropped the OPF; custom directory layout with a stale container.xml pointing at an old OPF location.
Related errors
- Invalid EPUB: missing container.xml
- Invalid EPUB: missing rootfile path
- Invalid PPTX: missing presentation.xml
- Invalid XLSX: missing workbook.xml
- Invalid DOCX: missing word/document.xml
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/e7a43dd5f6676924.
Report an issue: GitHub.