different-ai/openwork · error · Error
XLSX workbook.xml was not found.
Error message
XLSX workbook.xml was not found.
What it means
Error thrown while parsing an uploaded XLSX (Excel) attachment: the ZIP archive was opened but the required workbook.xml part is missing from it. This means the file is not a valid XLSX workbook — commonly it is a renamed CSV/XML file, an .xls (legacy binary) file renamed to .xlsx, a corrupted download, or an empty/partial file. Fix by re-exporting the file as a genuine .xlsx from Excel/LibreOffice and re-uploading.
Source
Thrown at apps/server/src/opencode-plugins/openwork-office-attachments.ts:633
...(formulaBlock ? { formula: xmlText(formulaBlock.inner) } : {}),
...(formulaBlock?.attributes.t ? { formulaType: formulaBlock.attributes.t } : {}),
...(formulaBlock?.attributes.ref ? { formulaRef: formulaBlock.attributes.ref } : {}),
...(rawValue !== undefined ? { rawValue } : {}),
...(displayValue !== undefined ? { displayedValue: displayValue } : {}),
});
}
return { dimension, mergedRanges, cells, omittedCells };
}
function quoted(value: string): string {
const encoded = JSON.stringify(value.length > 500 ? `${value.slice(0, 500)}…` : value);
return typeof encoded === "string" ? encoded : "\"\"";
}
function extractXlsxText(bytes: Buffer): string {
const entries = zipEntryMap(listZipEntries(bytes));
const workbookXml = readZipTextEntry(bytes, entries, "xl/workbook.xml");
if (!workbookXml) throw new Error("XLSX workbook.xml was not found.");
const sharedStrings = parseSharedStrings(readZipTextEntry(bytes, entries, "xl/sharedStrings.xml"));
const numberFormats = parseXlsxNumberFormats(readZipTextEntry(bytes, entries, "xl/styles.xml"));
const sheets = parseWorkbookSheets(workbookXml, readZipTextEntry(bytes, entries, "xl/_rels/workbook.xml.rels"));
if (sheets.length === 0) throw new Error("XLSX workbook contained no sheets.");
const lines = [
"xlsx_workbook:",
` sheet_count: ${sheets.length}`,
` shared_string_count: ${sharedStrings.length}`,
` style_count: ${numberFormats.length}`,
" sheets:",
];
let remainingCells = MAX_XLSX_CELLS;
for (const sheet of sheets.slice(0, MAX_XLSX_SHEETS)) {
lines.push(` - name: ${quoted(sheet.name)}`);
lines.push(` sheet_id: ${quoted(sheet.sheetId)}`);
if (sheet.relationshipId) lines.push(` relationship_id: ${quoted(sheet.relationshipId)}`);
lines.push(` path: ${quoted(sheet.path)}`);View on GitHub (pinned to 2b7df46e8a)
Solutions
- Open the file in Excel/LibreOffice and re-save it as a proper .xlsx, then retry.
- Verify the zip contains xl/workbook.xml at the root-relative path (unzip -l file.xlsx | grep workbook.xml).
- Ensure the upload is a real xlsx, not a renamed xls/csv/zip.
- Check the file isn't password-protected/encrypted.
- Re-create the archive preserving the original folder structure (OOXML root must contain [Content_Types].xml, xl/, etc.).
Example fix
// before: trusting the extension
if (file.name.endsWith(".xlsx")) return extractXlsxText(bytes);
// after: verify structure first
if (file.name.endsWith(".xlsx")) {
if (!zipHasEntry(bytes, "xl/workbook.xml")) throw new ApiError(400, "invalid_xlsx", "Not a valid XLSX workbook");
return extractXlsxText(bytes);
} Defensive patterns
Strategy: validation
Validate before calling
import { readFile } from "node:fs/promises";
async function looksLikeXlsx(path: string): Promise<boolean> {
const buf = await readFile(path);
return buf.subarray(0, 2).toString("latin1") === "PK" && buf.includes(Buffer.from("xl/workbook.xml"));
} Type guard
function hasWorkbookEntry(bytes: Buffer): boolean {
return bytes.includes(Buffer.from("xl/workbook.xml"));
} Try / catch
try {
const text = extractXlsxText(bytes);
} catch (err) {
if (err instanceof Error && err.message.includes("workbook.xml was not found")) {
throw new ApiError(400, "invalid_xlsx", "File is not a valid XLSX workbook; please re-save it from Excel.");
}
throw err;
} Prevention
- Validate file structure, not just the .xlsx extension, before extraction.
- Reject password-protected/encrypted workbooks up front with a clear message.
- Re-save files from Excel/LibreOffice if they came from nonstandard generators.
- Use unzip -l to confirm required OOXML parts during debugging.
When it happens
Trigger: extractOfficeText("xlsx", bytes) on a file whose zip lacks xl/workbook.xml — an empty or non-Office zip renamed to .xlsx, a badly re-zipped archive with a wrong root folder, or an encrypted workbook.
Common situations: Users renaming .zip/.xls to .xlsx; archives created without the xl/ folder prefix; password-protected workbooks stored encrypted; attachments corrupted so entries were dropped.
Related errors
- No supported Office XML text entries were found.
- XLSX workbook contained no sheets.
- ZIP central directory entry is out of bounds.
- ZIP entry ${name} uses unsupported compression method ${meth
- ZIP data for ${entry.name} is out of bounds.
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/6d5d89eb67da043b.
Report an issue: GitHub.