can1357/oh-my-pi · error · Error
Invalid XML: unterminated declaration
Error message
Invalid XML: unterminated declaration
What it means
Declarations and doctypes ("<!DOCTYPE ...>", "<![...]") are skipped by scanning to the next ">". If no ">" exists after "<!" before end-of-input, the parser throws this unterminated-declaration error.
Source
Thrown at packages/utils/src/docx/xml.ts:90
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");
const raw = source.slice(lessThan + 1, end).trim();
if (raw.startsWith("/")) {
if (stack.length === 1) throw new Error("Invalid XML: unexpected closing tag");
const closingName = raw.slice(1).trim();
const completed = stack.pop();
if (!completed || completed.name !== closingName)
throw new Error(`Invalid XML: mismatched closing tag ${closingName}`);
stack[stack.length - 1].children.push({
kind: "element",
name: completed.name,
attributes: completed.attributes,
children: completed.children,
});View on GitHub (pinned to 9690622007)
Solutions
- Close the declaration/doctype with ">" in the source XML.
- Verify the input isn't truncated; re-extract the DOCX entry or re-download the file.
- Remove unnecessary DOCTYPE declarations entirely if your generator doesn't need them.
- Validate the XML with a conforming parser before conversion.
Example fix
// before const xml = `<!DOCTYPE document [ <!ENTITY x "y" `; // after const xml = `<!DOCTYPE document [ <!ENTITY x "y" ]>`; parseXml(xml);
Defensive patterns
Strategy: validation
Validate before calling
function hasUnterminatedDeclaration(xml: string): boolean {
const m = /<![^>]*$/.exec(xml);
return m !== null;
}
if (hasUnterminatedDeclaration(xml)) throw new Error("XML has an unterminated declaration/doctype"); Try / catch
try {
const doc = parseXml(xml);
} catch (err) {
if (err instanceof Error && err.message === "Invalid XML: unterminated declaration") {
// strip the broken doctype line or reject the document
} else throw err;
} Prevention
- Drop DOCTYPE declarations unless strictly needed; the DOCX converter doesn't require them.
- Emit doctypes from a complete, tested template string.
- Verify input completeness (sizes/checksums) before parsing.
- Validate with a conforming XML parser before conversion.
When it happens
Trigger: Calling parseXml() on XML containing "<!" (DOCTYPE or other declaration) with no closing ">" — truncated doctype, hand-written XML missing the closing angle bracket, or content where the doctype was cut during preprocessing.
Common situations: Files truncated mid-DOCTYPE; do-it-yourself XML assembly that emits "<!DOCTYPE document [...]" and forgets the final ">"; regex-based edits that removed the closing bracket.
Related errors
- Invalid XML: unterminated comment
- Invalid XML: unterminated CDATA section
- Invalid XML: unterminated processing instruction
- 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/8ed1463f85392b11.
Report an issue: GitHub.