can1357/oh-my-pi · error · Error

Invalid XLSX: missing workbook.xml

Error message

Invalid XLSX: missing workbook.xml

What it means

The XLSX converter needs xl/workbook.xml to enumerate sheet names and their relationship ids. If the archive contains no such entry, convert() throws, since sheets cannot be resolved without it.

Source

Thrown at packages/coding-agent/src/markit/converters/xlsx.ts:73

		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 },
		});
		// Parse shared strings
		const ssXml = archiveEntryText(entries, "xl/sharedStrings.xml");
		const ss = ssXml ? (parser.parse(ssXml) as SharedStringsDoc) : null;
		const siList = ss?.sst?.si;
		const shared = toArray(siList);
		// Parse workbook for sheet names
		const wbXml = archiveEntryText(entries, "xl/workbook.xml");
		if (!wbXml) throw new Error("Invalid XLSX: missing workbook.xml");
		const wb = parser.parse(wbXml) as WorkbookDoc;
		const sheets = toArray(wb.workbook?.sheets?.sheet);
		// Parse workbook rels to map rIds to sheet files
		const relsXml = archiveEntryText(entries, "xl/_rels/workbook.xml.rels");
		const rels = relsXml ? (parser.parse(relsXml) as RelationshipsDoc) : null;
		const relList = toArray(rels?.Relationships?.Relationship);
		const relMap = new Map<string, string>();
		for (const r of relList) {
			relMap.set(r["@_Id"], r["@_Target"]);
		}
		const sections: string[] = [];
		for (const sheet of sheets) {
			const sheetName = sheet["@_name"];
			const rId = sheet["@_r:id"];
			const target = relMap.get(rId);
			if (!target) continue;
			const sheetPath = target.startsWith("/") ? target.slice(1) : `xl/${target}`;
			const sheetXml = archiveEntryText(entries, sheetPath);

View on GitHub (pinned to 9690622007)

Solutions

  1. Check with unzip -l file.xlsx that xl/workbook.xml exists; if not, the file is not a valid xlsx.
  2. Open and re-save in Excel/LibreOffice to produce a valid xlsx.
  3. Convert from the true source format (CSV/ODS) using the correct tool.
  4. If generating xlsx with a library, ensure the workbook part is written at xl/workbook.xml.

Example fix

// before
mv data.ods data.xlsx && markit data.xlsx
// after
soffice --headless --convert-to xlsx data.ods
markit data.xlsx
Defensive patterns

Strategy: validation

Validate before calling

async function isPlausibleXlsx(path: string, listEntries: (p: string) => Promise<string[]>): Promise<boolean> {
  const names = await listEntries(path);
  return names.includes("xl/workbook.xml") && names.includes("[Content_Types].xml");
}

Try / catch

try {
  const out = await markit.convertFile("data.xlsx");
} catch (err) {
  if (err instanceof Error && err.message === "Invalid XLSX: missing workbook.xml") {
    throw new Error("data.xlsx is not a valid OOXML workbook; re-export via Excel/LibreOffice");
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling the XLSX converter on a ZIP missing xl/workbook.xml.

Common situations: File is a renamed CSV/ODS or a raw SpreadsheetML/XML sheet, not an OOXML xlsx; a third-party writer produced an incomplete package; manual surgery on the xlsx dropped the workbook part; truncated download.

Related errors


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