different-ai/openwork · error · Error

Office XML exceeds the parser input limit.

Error message

Office XML exceeds the parser input limit.

What it means

assertSafeOfficeXml rejects an extracted Office XML part (e.g., word/document.xml) whose UTF-8 byte length exceeds MAX_ENTRY_UNCOMPRESSED_BYTES before handing it to the XML parser. This bounds memory/CPU from decompression bombs inside Office attachments.

Source

Thrown at apps/server/src/opencode-plugins/openwork-office-attachments.ts:351

function relevantXmlEntry(kind: OfficeKind, name: string): boolean {
  if (!name.endsWith(".xml")) return false;
  if (kind === "docx") {
    return name === "word/document.xml"
      || /^word\/header\d+\.xml$/.test(name)
      || /^word\/footer\d+\.xml$/.test(name)
      || name === "word/footnotes.xml"
      || name === "word/endnotes.xml"
      || name === "word/comments.xml";
  }
  return /^ppt\/slides\/slide\d+\.xml$/.test(name) || /^ppt\/notesSlides\/notesSlide\d+\.xml$/.test(name);
}

function compareEntryName(left: ZipEntry, right: ZipEntry): number {
  return left.name.localeCompare(right.name, undefined, { numeric: true, sensitivity: "base" });
}

function assertSafeOfficeXml(xml: string): void {
  if (Buffer.byteLength(xml, "utf8") > MAX_ENTRY_UNCOMPRESSED_BYTES) throw new Error("Office XML exceeds the parser input limit.");
  const lower = xml.toLowerCase();
  if (lower.includes("<!doctype") || lower.includes("<!entity")) throw new Error("Office XML DTD and entity declarations are not supported.");
}

function xmlLocalName(name: string): string {
  const colon = name.lastIndexOf(":");
  return (colon === -1 ? name : name.slice(colon + 1)).toLowerCase();
}

function parsedXmlText(xml: string, tagSeparator: string): string {
  assertSafeOfficeXml(xml);
  let text = "";
  let omittedDepth = 0;
  const omittedSeparator = tagSeparator || " ";
  const parser = new Parser({
    onopentag(name) {
      if (omittedDepth > 0) {
        omittedDepth += 1;

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Reduce document size or split it before attaching.
  2. Raise MAX_ENTRY_UNCOMPRESSED_BYTES if legitimate large documents must be supported (mind memory limits).
  3. Pre-check the attachment's uncompressed size upstream and reject oversized files with a clear message.
  4. If zip bombs are a concern, keep the limit and reject the attachment.

Example fix

// before
const MAX_ENTRY_UNCOMPRESSED_BYTES = 5 * 1024 * 1024;
// after: allow larger legitimate documents
const MAX_ENTRY_UNCOMPRESSED_BYTES = 20 * 1024 * 1024;
Defensive patterns

Strategy: validation

Validate before calling

import { stat } from "node:fs/promises";
const MAX_ENTRY_UNCOMPRESSED_BYTES = 5 * 1024 * 1024;
async function officeFileWithinLimits(path: string): Promise<boolean> {
  const { size } = await stat(path);
  return size <= MAX_ENTRY_UNCOMPRESSED_BYTES * 10; // coarse pre-check on compressed size
}

Type guard

function xmlWithinLimit(xml: string, limit = MAX_ENTRY_UNCOMPRESSED_BYTES): boolean {
  return Buffer.byteLength(xml, "utf8") <= limit;
}

Try / catch

try {
  const text = extractOfficeText(kind, bytes);
} catch (err) {
  if (err instanceof Error && err.message.includes("parser input limit")) {
    throw new ApiError(413, "attachment_too_large", "Document XML exceeds the extraction size limit.");
  }
  throw err;
}

Prevention

When it happens

Trigger: extractOfficeText encounters an XML entry (docx/pptx) that inflates to more than MAX_ENTRY_UNCOMPRESSED_BYTES bytes — a huge document or a zip-bomb style archive.

Common situations: Very large documents exceeding the configured limit; malicious zip-bomb attachments disguised as office files; misconfigured limit after reducing it for memory pressure.

Related errors


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/e0a384af38ec6070. Report an issue: GitHub.