Summary
renderDocx (document-converter, engine pi-doc-engine:0.1.0) produces a DOCX that neither Word nor LibreOffice can open when the template contains a cover-page section. The generated word/document.xml keeps the template's original header/footer relationship IDs in the first <w:sectPr>, while word/_rels/document.xml.rels is rewritten with a shifted (off-by-one) numbering — leaving a dangling rId15.
LibreOffice fails with the unhelpful Error: source file could not be loaded; the file passes unzip -t and every part is well-formed XML, so the corruption is not obvious.
Repro
const dc = createDocumentConverter({ image: "pi-doc-engine:0.1.0", stagingDir: "/tmp/kb-staging" });
await dc.renderDocx("/abs/doc.md", {
output: "/abs/doc.docx",
template: "default",
templatesDir: "/abs/docs/templates", // template with enable_cover_page: true
});
Frontmatter: template: default, enable_cover_page: true, language: hu, toc.enabled: true.
Then: soffice --headless --convert-to pdf doc.docx → Error: source file could not be loaded.
Evidence from the produced package
word/_rels/document.xml.rels (rewritten by the engine):
| rId |
target |
| rId9 |
header2.xml |
| rId10 |
header1.xml |
| rId11 |
header3.xml |
| rId12 |
footer2.xml |
| rId13 |
footer1.xml |
| rId14 |
footer3.xml |
word/document.xml — sectPr #0 (the template's cover section, left untouched):
<w:sectPr ...>
<w:headerReference w:type="even" r:id="rId10"/>
<w:headerReference w:type="default" r:id="rId11"/>
<w:footerReference w:type="even" r:id="rId12"/>
<w:footerReference w:type="default" r:id="rId13"/>
<w:headerReference w:type="first" r:id="rId14"/>
<w:footerReference w:type="first" r:id="rId15"/> <!-- DANGLING: no rId15 in rels -->
sectPr #1 (engine-generated, correct — consistent with the rels table):
<w:headerReference r:id="rId10" w:type="even"/>
<w:headerReference r:id="rId9" w:type="default"/>
<w:footerReference r:id="rId13" w:type="even"/>
<w:footerReference r:id="rId12" w:type="default"/>
<w:headerReference r:id="rId11" w:type="first"/>
<w:footerReference r:id="rId14" w:type="first"/>
So sectPr #0 references rId10..rId15 (the template's original ids) while the rels were renumbered to rId9..rId14 — shifted by one, and the semantics are wrong too (headerReference type="first" → rId14 = footer3).
Bisect that isolated it
Replacing the body with a single <w:p> while keeping the same package → loads fine. Adding only sectPr #0 back → fails. Rewriting sectPr #0's six refs to the same ids as sectPr #1 → DOCX opens and converts to PDF correctly.
Expected
Every r:id in all <w:sectPr> elements copied from the template must be remapped to the ids actually written into word/_rels/document.xml.rels. Ideally the engine should also validate that no r:id in document.xml is dangling before writing the output (fail loudly, not silently produce an unopenable file).
Environment
@blackbelt-technology/pi-dashboard-document-converter 0.7.0, engine image pi-doc-engine:0.1.0
- dashboard
develop @ 37d63b0
- macOS arm64, LibreOffice 25.x (host) and the containerized LibreOffice — both refuse the file
Summary
renderDocx(document-converter, enginepi-doc-engine:0.1.0) produces a DOCX that neither Word nor LibreOffice can open when the template contains a cover-page section. The generatedword/document.xmlkeeps the template's original header/footer relationship IDs in the first<w:sectPr>, whileword/_rels/document.xml.relsis rewritten with a shifted (off-by-one) numbering — leaving a danglingrId15.LibreOffice fails with the unhelpful
Error: source file could not be loaded; the file passesunzip -tand every part is well-formed XML, so the corruption is not obvious.Repro
Frontmatter:
template: default,enable_cover_page: true,language: hu,toc.enabled: true.Then:
soffice --headless --convert-to pdf doc.docx→Error: source file could not be loaded.Evidence from the produced package
word/_rels/document.xml.rels(rewritten by the engine):word/document.xml— sectPr #0 (the template's cover section, left untouched):sectPr #1 (engine-generated, correct — consistent with the rels table):
So sectPr #0 references
rId10..rId15(the template's original ids) while the rels were renumbered torId9..rId14— shifted by one, and the semantics are wrong too (headerReference type="first"→rId14= footer3).Bisect that isolated it
Replacing the body with a single
<w:p>while keeping the same package → loads fine. Adding only sectPr #0 back → fails. Rewriting sectPr #0's six refs to the same ids as sectPr #1 → DOCX opens and converts to PDF correctly.Expected
Every
r:idin all<w:sectPr>elements copied from the template must be remapped to the ids actually written intoword/_rels/document.xml.rels. Ideally the engine should also validate that nor:idindocument.xmlis dangling before writing the output (fail loudly, not silently produce an unopenable file).Environment
@blackbelt-technology/pi-dashboard-document-converter0.7.0, engine imagepi-doc-engine:0.1.0develop@ 37d63b0