{"record":{"id":"6e6a7372c21ba5e5","repo":"langchain-ai/langchain","slug":"failed-to-parse-xml-format-from-completion-text","errorCode":null,"errorMessage":"Failed to parse XML format from completion {text}. Got: {e}","messagePattern":"Failed to parse XML format from completion (.+?)\\. Got: (.+?)","errorType":"exception","errorClass":"OutputParserException","httpStatus":null,"severity":"error","filePath":"libs/core/langchain_core/output_parsers/xml.py","lineNumber":251,"sourceCode":"            et = ElementTree  # Use the defusedxml parser\n        else:\n            et = ET  # Use the standard library parser\n\n        match = re.search(r\"```(xml)?(.*)```\", text, re.DOTALL)\n        if match is not None:\n            # If match found, use the content within the backticks\n            text = match.group(2)\n        encoding_match = self.encoding_matcher.search(text)\n        if encoding_match:\n            text = encoding_match.group(2)\n\n        text = text.strip()\n        try:\n            root = et.fromstring(text)\n            return self._root_to_dict(root)\n        except et.ParseError as e:\n            msg = f\"Failed to parse XML format from completion {text}. Got: {e}\"\n            raise OutputParserException(msg, llm_output=text) from e\n\n    @override\n    def _transform(self, input: Iterator[str | BaseMessage]) -> Iterator[AddableDict]:\n        streaming_parser = _StreamingParser(self.parser)\n        for chunk in input:\n            yield from streaming_parser.parse(chunk)\n        streaming_parser.close()\n\n    @override\n    async def _atransform(\n        self, input: AsyncIterator[str | BaseMessage]\n    ) -> AsyncIterator[AddableDict]:\n        streaming_parser = _StreamingParser(self.parser)\n        async for chunk in input:\n            for output in streaming_parser.parse(chunk):\n                yield output\n        streaming_parser.close()\n","sourceCodeStart":233,"sourceCodeEnd":269,"githubUrl":"https://github.com/langchain-ai/langchain/blob/e32fa9a52eab3b61ad7a45399bfde59b3e580fc4/libs/core/langchain_core/output_parsers/xml.py#L233-L269","documentation":"OutputParserException raised by XMLOutputParser.parse when et.fromstring raises ParseError: after extracting optional fenced code blocks and encoding declarations and stripping whitespace, the text is still not well-formed XML. The original text is attached via llm_output for debugging.","triggerScenarios":"LLM returns malformed XML: unclosed tags, XML-ish prose without a single root element, markdown bullet fragments like '- <tag>value' where '-' precedes the root, multiple sibling root elements, or unescaped & characters.","commonSituations":"Prompting 'return XML' without an example; models wrapping XML in explanations; truncation by max_tokens cutting the closing tag; special characters (&, <) not escaped in values.","solutions":["Use XMLOutputParser's get_format_instructions()/prompt template so the model sees the exact expected format and encoding","Increase max_tokens so closing tags are not truncated","Catch OutputParserException, inspect llm_output, and retry with corrective feedback or strip non-XML prefix/suffix before re-parsing"],"exampleFix":"# before\nprompt = \"Give me people and their favorite foods in XML.\"\nchain = prompt | llm | XMLOutputParser()\n\n# after\nparser = XMLOutputParser()\nprompt = PromptTemplate(\n    template=\"Answer the user query.\\n{format_instructions}\\n{query}\",\n    input_variables=[\"query\"],\n    partial_variables={\"format_instructions\": parser.get_format_instructions()},\n)\nchain = prompt | llm | parser","handlingStrategy":"retry","validationCode":"import re\n\ndef looks_like_xml(text: str) -> bool:\n    text = text.strip()\n    m = re.search(r\"```(?:xml)?(.*)```\", text, re.DOTALL)\n    if m:\n        text = m.group(1)\n    return bool(re.search(r\"<[a-zA-Z:_][^>]*>\", text))","typeGuard":null,"tryCatchPattern":"from langchain_core.exceptions import OutputParserException\ntry:\n    out = parser.invoke(text)\nexcept OutputParserException as e:\n    raw = e.llm_output  # original text for repair\n    out = parser.invoke(f\"<filtered>{strip_non_xml(raw)}</filtered>\")  # repair & retry","preventionTips":["Always inject parser.get_format_instructions() into the prompt","Ensure max_tokens covers the full XML including closing tags"],"tags":["xml","output-parsing","model-behavior"],"backgroundTag":null,"analyzedSha":"e32fa9a52eab3b61ad7a45399bfde59b3e580fc4","analyzedAt":"2026-08-14T18:42:09.092Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}