hubeiqiao/tim-project-skills/python-docx-style-id-mismatch
Claude Code and agent skill by hubeiqiao/tim-project-skills
- community
Checking that the SKILL.md file is still in the repository.
Use when python-docx paragraphs created via OxmlElement ignore the intended style or fall back to Normal - explains the style-name vs style-ID mismatch, shows the fix, and notes the related section-break removal pitfall.
Install
npx vskill@latest install hubeiqiao/tim-project-skills/python-docx-style-id-mismatchSKILL.md
python-docx Style ID Mismatch (OxmlElement)
What This Skill Helps With
Use this skill when your low-level python-docx XML edits look correct in code but Word still renders the paragraph as Normal instead of the heading or list style you expected.
Ask for this skill with prompts like
Use $python-docx-style-id-mismatch to fix why my Heading 2 paragraphs render as Normal.Use $python-docx-style-id-mismatch to explain the difference between style names and style IDs in python-docx.Use $python-docx-style-id-mismatch to review this OxmlElement paragraph insertion code.
Problem
When creating Word document paragraphs using python-docx's low-level OxmlElement API, setting w:pStyle with the style's display name (e.g., "Heading 2") causes the paragraph to silently fall back to "Normal" style. No error is raised. The XML requires the style ID (e.g., "Heading2") which differs from the display name.
Context / Trigger Conditions
- Creating paragraphs via
OxmlElement('w:p')instead ofdoc.add_paragraph() - Setting style with
pStyle.set(qn('w:val'), 'Heading 2')(WITH space) - Paragraphs render as Normal/body text instead of the intended style
paragraph.style.nameshows "Normal" even though you set a heading style- No error or warning is raised -- complete silent failure
- Affects all styles with spaces in their display names
Root Cause
python-docx has two name systems:
- Display name (
style.name): Human-readable, e.g., "Heading 2", "List Bullet", "Body Text" - XML style ID (
style.style_id): Used in the XML, e.g., "Heading2", "ListBullet", "BodyText"
When you use doc.add_paragraph(style='Heading 2'), python-docx handles the mapping internally. But when using OxmlElement directly to set w:pStyle, you must provide the XML style ID.
Solution
Create a mapping dictionary and helper function:
Then use it when setting styles via OxmlElement:
The fallback style_name.replace(' ', '') handles most cases since Word typically just removes spaces, but some styles have non-obvious IDs (e.g., "table of figures" -> "TableofFigures" with different casing).
Verification
After applying the fix, verify styles are correctly assigned:
If headings appear as "Normal" in this output, the style ID is wrong.
To inspect what XML style ID a document actually uses:
Related Issue: Section Breaks Lost During Paragraph Removal
When removing paragraphs between chapter boundaries using lxml's body.remove(element), any w:sectPr elements embedded in paragraph properties (w:pPr) are removed along with the paragraphs. This silently destroys section breaks (used for Roman/Arabic page numbering).
Fix: After content replacement operations, verify section count and re-add section breaks if needed:
Example
Full pattern for creating a heading paragraph via OxmlElement:
Notes
- This only affects the low-level OxmlElement API. Using
doc.add_paragraph(style='Heading 2') works correctly because python-docx resolves the name internally.
- The OxmlElement approach is necessary when inserting paragraphs at
specific positions (before a reference element) rather than appending to the end.
- Custom styles defined in a document may have arbitrary IDs. Always
check style.style_id for the actual XML ID if unsure.
- The
style_name.replace(' ', '')heuristic works for ~95% of built-in
Word styles but won't catch casing differences.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/python-docx-style-id-mismatch/SKILL.md
Popularity
- Repository stars
- 1
- 7-day trend score
- 3
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/hubeiqiao/tim-project-skills/python-docx-style-id-mismatch)