can1357/oh-my-pi · error · Error
Invalid XML: unterminated CDATA section
Error message
Invalid XML: unterminated CDATA section
What it means
The XML parser handles "<![CDATA[ ... ]]>" sections as raw text. When a CDATA opener lacks its closing "]]>" before end-of-input, the parser cannot determine the section boundary and throws this error from parseXml.
Source
Thrown at packages/utils/src/docx/xml.ts:77
const lessThan = source.indexOf("<", offset);
if (lessThan === -1) {
const value = decodeEntities(source.slice(offset));
if (value) stack[stack.length - 1].children.push({ kind: "text", value });
break;
}
if (lessThan > offset) {
const value = decodeEntities(source.slice(offset, lessThan));
if (value) stack[stack.length - 1].children.push({ kind: "text", value });
}
if (source.startsWith("<!--", lessThan)) {
const end = source.indexOf("-->", lessThan + 4);
if (end === -1) throw new Error("Invalid XML: unterminated comment");
offset = end + 3;
continue;
}
if (source.startsWith("<![CDATA[", lessThan)) {
const end = source.indexOf("]]>", lessThan + 9);
if (end === -1) throw new Error("Invalid XML: unterminated CDATA section");
stack[stack.length - 1].children.push({ kind: "text", value: source.slice(lessThan + 9, end) });
offset = end + 3;
continue;
}
if (source.startsWith("<?", lessThan)) {
const end = source.indexOf("?>", lessThan + 2);
if (end === -1) throw new Error("Invalid XML: unterminated processing instruction");
offset = end + 2;
continue;
}
if (source.startsWith("<!", lessThan)) {
const end = source.indexOf(">", lessThan + 2);
if (end === -1) throw new Error("Invalid XML: unterminated declaration");
offset = end + 1;
continue;
}
const end = source.indexOf(">", lessThan + 1);
if (end === -1) throw new Error("Invalid XML: unterminated tag");View on GitHub (pinned to 9690622007)
Solutions
- Ensure every "<![CDATA[" section ends with "]]>" in the source XML.
- Re-extract or re-download the file — verify the XML part isn't truncated.
- If embedding arbitrary text, escape XML entities instead of relying on CDATA, or split text containing "]]>" across two CDATA sections.
- Validate the XML part with a strict parser before feeding it to the converter to get a clearer diagnostic.
Example fix
// before const xml = `<doc><![CDATA[ 1 < 2 `; parseXml(xml); // throws // after const xml = `<doc><![CDATA[ 1 < 2 ]]></doc>`; parseXml(xml);
Defensive patterns
Strategy: validation
Validate before calling
function hasUnterminatedCdata(xml: string): boolean {
return (xml.match(/<!\[CDATA\[/g)?.length ?? 0) > (xml.match(/\]\]>/g)?.length ?? 0);
}
if (hasUnterminatedCdata(xml)) throw new Error("XML has an unterminated CDATA section"); Try / catch
try {
const doc = parseXml(xml);
} catch (err) {
if (err instanceof Error && err.message === "Invalid XML: unterminated CDATA section") {
// reject the document or repair by appending "]]>" before the next tag
} else throw err;
} Prevention
- Escape text with entities (<, &) instead of CDATA when possible.
- Split any content containing "]]>" into adjacent CDATA sections: `...]]]]><![CDATA[>...`.
- Verify files aren't truncated before parsing.
- Run a strict XML validation pass before feeding documents to the converter.
When it happens
Trigger: Calling parseXml() (directly or via convertToHtml) on XML with "<![CDATA[" without a closing "]]>" — truncated files, generated XML with unterminated CDATA, or content containing literal "]]>" handling mistakes that ate the closer.
Common situations: Escaped code/sample text embedded in DOCX documents where the closing bracket was lost in preprocessing; XML assembled by concatenation that dropped the terminator; truncated entries in a damaged archive.
Related errors
- Invalid XML: unterminated comment
- Invalid XML: unterminated processing instruction
- Invalid XML: unterminated declaration
- Invalid XML: unterminated tag
- Invalid XML: unexpected closing tag
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/487cfefc5b5c7ad4.
Report an issue: GitHub.