docx skill: docx-js output has no default "Normal" paragraph style, breaks python-docx readers

Status Open
Maintainer reply None cached
Activity 0 comments · opened Aug 31, 2026

Summary

When the docx skill generates a .docx via its docx-js code path (docx npm package, observed v9.7.1) without an explicit styles option, the resulting styles.xml has no "Normal" paragraph style at all — and no paragraph style is marked as the document default. Any tool built on python-docx that reads paragraph.style.name on an unstyled paragraph then crashes with AttributeError: 'NoneType' object has no attribute 'name', because python-docx's Styles.default(WD_STYLE_TYPE.PARAGRAPH) returns None when nothing is marked default — it does not fall back to Word's own w:docDefaults behavior.

Reproduction

const { Document, Paragraph, TextRun, Packer } = require("docx"); // v9.7.1
const doc = new Document({
  sections: [{ children: [new Paragraph({ children: [new TextRun("hello")] })] }],
});
Packer.toBuffer(doc).then(buf => require("fs").writeFileSync("out.docx", buf));

Inspecting out.docx's word/styles.xml shows only Title, Heading1-6, Strong, ListParagraph, Hyperlink, FootnoteReference, FootnoteText, FootnoteTextChar, EndnoteReference, EndnoteText, EndnoteTextChar — no Normal, and nothing marked w:default="1" for a paragraph-type style. DefaultStylesFactory.newInstance() in this version of docx simply never emits one.

from docx import Document
d = Document("out.docx")
p = d.paragraphs[0]
p.style        # None
p.style.name   # AttributeError: 'NoneType' object has no attribute 'name'

Fix that works

Pass an explicit styles.paragraphStyles entry for "Normal" in the Document constructor, and set style: "Normal" on every Paragraph that isn't a heading/bullet (including paragraphs used as table-cell content or as empty spacers):

const doc = new Document({
  styles: {
    paragraphStyles: [{
      id: "Normal", name: "Normal", quickFormat: true,
      run: { font: "Calibri", size: 22 },
      paragraph: { spacing: { line: 276 } },
    }],
  },
  sections: [{ children: [new Paragraph({ style: "Normal", children: [new TextRun("hello")] })] }],
});

With every paragraph carrying an explicit w:pStyle, python-docx resolves paragraph.style.name correctly ("Normal").

Ask

Document this in the docx skill's SKILL.md "Creating with docx-js" gotchas (or fix DefaultStylesFactory upstream in the vendored docx package to always emit a default Normal style, matching what python-docx/Word themselves guarantee). This affects any downstream tooling built on python-docx that touches paragraph.style on docx-js output — not just a cosmetic styling gap.

Environment

  • docx npm package v9.7.1, resolved via the docx skill's own scratchpad node_modules
  • python-docx (current PyPI release as of 2026-08)
  • Windows 11, Claude Code CLI

View original on GitHub ↗