can1357/oh-my-pi · error · Error

Invalid EPUB: missing rootfile path

Error message

Invalid EPUB: missing rootfile path

What it means

After parsing META-INF/container.xml, the converter extracts the rootfile's full-path attribute, which points at the package document (content.opf). If container.xml parses but contains no rootfile element or an empty full-path, convert() throws this error: the container declares no usable package document.

Source

Thrown at packages/coding-agent/src/markit/converters/epub.ts:69

		if (streamInfo.mimetype && MIMETYPES.some(m => streamInfo.mimetype?.startsWith(m))) return true;
		return false;
	}

	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>();

View on GitHub (pinned to 9690622007)

Solutions

  1. Inspect META-INF/container.xml and ensure it has <rootfiles><rootfile full-path="OEBPS/content.opf" media-type="application/oebps-package+xml"/></rootfiles>.
  2. Validate the EPUB with epubcheck and fix reported container issues.
  3. Re-export/re-download the EPUB from a known-good source.
  4. If you control generation, fix the tool writing container.xml to emit the rootfile element.

Example fix

// before (broken container.xml)
<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container"><rootfiles/></container>
// after
<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container"><rootfiles><rootfile full-path="OEBPS/content.opf" media-type="application/oebps-package+xml"/></rootfiles></container>
Defensive patterns

Strategy: validation

Validate before calling

async function hasEpubRootfile(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");
  if (!containerXml?.includes("<rootfile")) return false;
  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 rootfile path") {
    throw new Error("book.epub container.xml has no <rootfile full-path>; rebuild the EPUB");
  }
  throw err;
}

Prevention

When it happens

Trigger: container.xml exists but is empty, malformed (so container.container?.rootfiles?.rootfile is undefined), or its <rootfile> lacks the full-path attribute.

Common situations: Hand-edited or generator-broken container.xml; namespace/structure mismatch confusing the XML parser into a different shape; EPUB produced by a buggy tooling pipeline that wrote an empty rootfiles element.

Related errors


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