can1357/oh-my-pi · error · Error

Invalid DOCX: missing word/document.xml

Error message

Invalid DOCX: missing word/document.xml

What it means

convertToHtml() reads the DOCX (a ZIP archive) and requires the core part word/document.xml, which holds the document content. If the archive has no such entry, the file is not a valid Office Open XML word-processing document, and the converter throws this error instead of attempting to parse.

Source

Thrown at packages/utils/src/docx/converter.ts:660

		else contents = `${contents.slice(0, lastParagraph)} ${backlink}${contents.slice(lastParagraph)}`;
		html += `<li id="footnote-${escapeAttribute(note.id)}">${contents}</li>`;
	}
	return `${html}</ol>`;
}

function defaultImageConverter(): ImageConverter {
	return images.imgElement(async image => ({
		alt: image.altText,
		src: `data:${image.contentType};base64,${await image.read("base64")}`,
	}));
}

/** Convert a DOCX buffer or path to mammoth-compatible HTML. */
export async function convertToHtml(input: DocxInput, options: ConvertToHtmlOptions = {}): Promise<DocxResult> {
	const bytes = "buffer" in input && input.buffer ? input.buffer : await fs.readFile(input.path);
	const entries = await readArchiveEntries({ bytes, format: "zip" });
	const documentXml = archiveEntryText(entries, "word/document.xml");
	if (!documentXml) throw new Error("Invalid DOCX: missing word/document.xml");
	const context: ConversionContext = {
		entries,
		relationships: parseRelationships(archiveEntryText(entries, "word/_rels/document.xml.rels")),
		contentTypes: parseContentTypes(archiveEntryText(entries, "[Content_Types].xml")),
		styles: parseStyles(archiveEntryText(entries, "word/styles.xml")),
		numbering: parseNumbering(archiveEntryText(entries, "word/numbering.xml")),
		messages: [],
		warnedStyles: new Set(),
		customStyles: parseCustomStyles(options.styleMap),
		includeDefaultStyleMap: options.includeDefaultStyleMap !== false,
		convertImage: options.convertImage ?? defaultImageConverter(),
		footnotes: parseFootnotes(archiveEntryText(entries, "word/footnotes.xml")),
		usedFootnotes: [],
		footnoteOrdinals: new Map(),
	};
	const document = parseXml(documentXml);
	const body = firstChild(document, "body");
	if (!body) throw new Error("Invalid DOCX: missing document body");

View on GitHub (pinned to 9690622007)

Solutions

  1. Verify the input is a genuine DOCX: it must be a ZIP containing word/document.xml (`unzip -l file.docx | grep word/document.xml`).
  2. Re-export/re-save the file as .docx from Word/LibreOffice rather than renaming another format.
  3. Handle legacy formats first: convert .doc/.rtf with an external tool (LibreOffice headless, pandoc) before calling convertToHtml.
  4. Check file size and that the upload/download completed; re-fetch the file if it is truncated or 0 bytes.

Example fix

// before
const html = await convertToHtml({ path: "report.doc" }); // renamed, throws

// after
const out = await $`soffice --headless --convert-to docx report.doc`;
const html = await convertToHtml({ path: "report.docx" });
Defensive patterns

Strategy: validation

Validate before calling

async function isLikelyDocx(path: string): Promise<boolean> {
  try {
    const fd = await fs.open(path, "r");
    const buf = Buffer.alloc(4);
    await fd.read(buf, 0, 4, 0);
    await fd.close();
    return buf.equals(Buffer.from("PK\x03\x04"));
  } catch { return false; }
}
if (!(await isLikelyDocx(inputPath))) throw new Error("not a DOCX (ZIP) file");

Try / catch

try {
  const result = await convertToHtml(input);
} catch (err) {
  if (err instanceof Error && err.message === "Invalid DOCX: missing word/document.xml") {
    // fall back to an external converter (libreoffice/pandoc) or surface a format error to the user
  } else throw err;
}

Prevention

When it happens

Trigger: Calling convertToHtml() on a buffer or file that is not a real DOCX: a renamed .doc/.rtf/.txt/HTML file, a ZIP missing word/document.xml, a corrupt or truncated download, or an empty/password-protected archive.

Common situations: Users renaming report.doc or .rtf to .docx; passing the flat OPC XML (.xml) instead of the packaged .docx; partially uploaded files in a web pipeline; encrypted DOCX from enterprise templates.

Related errors


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