different-ai/openwork · error · Error

No supported Office XML text entries were found.

Error message

No supported Office XML text entries were found.

What it means

For docx/pptx (non-xlsx) extraction, extractOfficeText filters zip entries through relevantXmlEntry (e.g., word/*.xml, ppt/*.xml) and throws when no qualifying XML part exists. The file is either not the claimed Office kind or has no textual parts.

Solutions

  1. Verify the OfficeKind passed matches the actual file type (docx vs pptx).
  2. Confirm the zip contains word/document.xml or ppt/ XML parts (unzip -l).
  3. Re-save the file from Word/PowerPoint as a standard .docx/.pptx.
  4. Check the file isn't password-protected/encrypted (encrypted OOXML is an OLE container, not a zip with XML parts).

Example fix

// before: kind inferred from user-supplied label
extractOfficeText(userKind, bytes);
// after: detect kind from content
const kind = detectOfficeKind(bytes); // checks presence of word/ vs ppt/ parts
extractOfficeText(kind, bytes);
Defensive patterns

Strategy: validation

Validate before calling

function detectOfficeKind(bytes: Buffer): "docx" | "pptx" | "xlsx" | null {
  if (bytes.includes(Buffer.from("word/document.xml"))) return "docx";
  if (bytes.includes(Buffer.from("ppt/presentation.xml"))) return "pptx";
  if (bytes.includes(Buffer.from("xl/workbook.xml"))) return "xlsx";
  return null;
}

Type guard

function hasRelevantXmlParts(bytes: Buffer): boolean {
  return bytes.includes(Buffer.from("word/")) || bytes.includes(Buffer.from("ppt/"));
}

Try / catch

try {
  const text = extractOfficeText(kind, bytes);
} catch (err) {
  if (err instanceof Error && err.message.includes("No supported Office XML text entries")) {
    throw new ApiError(400, "invalid_office_file", "No readable document parts found; re-save the file from Office.");
  }
  throw err;
}

Prevention

When it happens

Trigger: extractOfficeText("docx"|"pptx", bytes) on a zip with no entries ending in the relevant XML paths — renamed zip, wrong kind passed (e.g., docx bytes parsed as pptx), encrypted OOXML, or an archive missing its word//ppt/ parts.

Common situations: Renamed files (zip/html saved as .docx); passing the wrong OfficeKind to extractOfficeText; DRM/encrypted Office files; minimal OOXML containers with no document parts.

Related errors


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

Appendix: source

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

      lines.push(`      type: ${quoted(cell.type)}`);
      if (cell.rawValue !== undefined) lines.push(`      raw_value: ${quoted(cell.rawValue)}`);
      if (cell.displayedValue !== undefined) lines.push(`      displayed_value: ${quoted(cell.displayedValue)}`);
      if (cell.formula) lines.push(`      formula: ${quoted(cell.formula)}`);
      if (cell.formulaType) lines.push(`      formula_type: ${quoted(cell.formulaType)}`);
      if (cell.formulaRef) lines.push(`      formula_ref: ${quoted(cell.formulaRef)}`);
      if (cell.styleIndex !== undefined) lines.push(`      style_index: ${quoted(cell.styleIndex)}`);
      if (cell.numberFormat) lines.push(`      number_format: ${quoted(cell.numberFormat)}`);
    }
    if (data.omittedCells > 0) lines.push(`    omitted_cells: ${data.omittedCells}`);
  }
  if (sheets.length > MAX_XLSX_SHEETS) lines.push(`  omitted_sheets: ${sheets.length - MAX_XLSX_SHEETS}`);
  return lines.join("\n").slice(0, MAX_EXTRACTED_TEXT_CHARS);
}

function extractOfficeText(kind: OfficeKind, bytes: Buffer): string {
  if (kind === "xlsx") return extractXlsxText(bytes);
  const entries = listZipEntries(bytes).filter((entry) => relevantXmlEntry(kind, entry.name)).sort(compareEntryName);
  if (entries.length === 0) throw new Error("No supported Office XML text entries were found.");
  const pieces: string[] = [];
  let remaining = MAX_EXTRACTED_TEXT_CHARS;
  for (const entry of entries) {
    if (remaining <= 0) break;
    const text = xmlText(readZipEntryData(bytes, entry).toString("utf8"));
    if (!text) continue;
    const chunk = text.slice(0, remaining);
    pieces.push(`[${entry.name}]\n${chunk}`);
    remaining -= chunk.length;
  }
  const combined = pieces.join("\n\n").slice(0, MAX_EXTRACTED_TEXT_CHARS);
  if (!combined) throw new Error("Office XML text entries contained no extractable text.");
  return combined;
}

function basePartIds(part: Record<string, unknown>): Record<string, unknown> {
  const result: Record<string, unknown> = {};
  for (const key of ["id", "sessionID", "messageID", "sessionId", "messageId"]) {

View on GitHub (pinned to 2b7df46e8a)