{"record":{"id":"465247cb50cc1dfb","repo":"angular/angular","slug":"the-xml-file-does-not-contain-a-rootnodename","errorCode":null,"errorMessage":"The XML file does not contain a <${rootNodeName}> root node.","messagePattern":"The XML file does not contain a <(.+?)> root node\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/localize/tools/src/translate/translation_files/translation_parsers/translation_utils.ts","lineNumber":113,"sourceCode":"  rootNodeName: string,\n  attributes: Record<string, string>,\n): ParseAnalysis<XmlTranslationParserHint> {\n  const diagnostics = new Diagnostics();\n  const xmlParser = new XmlParser();\n  const xml = xmlParser.parse(contents, filePath);\n\n  if (\n    xml.rootNodes.length === 0 ||\n    xml.errors.some((error) => error.level === ParseErrorLevel.ERROR)\n  ) {\n    xml.errors.forEach((e) => addParseError(diagnostics, e));\n    return {canParse: false, diagnostics};\n  }\n\n  const rootElements = xml.rootNodes.filter(isNamedElement(rootNodeName));\n  const rootElement = rootElements[0];\n  if (rootElement === undefined) {\n    diagnostics.warn(`The XML file does not contain a <${rootNodeName}> root node.`);\n    return {canParse: false, diagnostics};\n  }\n\n  for (const attrKey of Object.keys(attributes)) {\n    const attr = rootElement.attrs.find((attr) => attr.name === attrKey);\n    if (attr === undefined || attr.value !== attributes[attrKey]) {\n      addParseDiagnostic(\n        diagnostics,\n        rootElement.sourceSpan,\n        `The <${rootNodeName}> node does not have the required attribute: ${attrKey}=\"${attributes[attrKey]}\".`,\n        ParseErrorLevel.WARNING,\n      );\n      return {canParse: false, diagnostics};\n    }\n  }\n\n  if (rootElements.length > 1) {\n    xml.errors.push(","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/angular/angular/blob/51cb07e98081ab7e4e84a9e0949266a8e19cca84/packages/localize/tools/src/translate/translation_files/translation_parsers/translation_utils.ts#L95-L131","documentation":"`canParseXml()` - shared by the XLIFF 1.2, XLIFF 2.0, and XTB parsers - parsed the file as XML without ERROR-level problems, but found no root element with the expected name (`xliff`, `xliffv2`, or `translationbundle`). It returns canParse=false with this warning so the loader can attempt the next parser.","triggerScenarios":"Passing an XML translation file whose root element does not match the format the parser expects: an XLIFF 2.0 file when the XLIFF 1.2 parser inspects it (or vice versa), an XTB file inspected by an XLIFF parser, or any XML doc with a different root.","commonSituations":"Mixing XLIFF versions between what the extraction produced and what translation was configured for; a vendor/tool exporting a wrapper XML; manually restructured files.","solutions":["Open the file and check the actual root element and its version attribute (e.g. `<xliff version=\"1.2\">` vs `<xliff version=\"2.0\" xmlns=\"urn:oasis:names:tc:xliff:document:2.0\">`).","Regenerate the file with the serializer format that matches the file you intend to use (`ng extract-i18n --format=xlf|xlf2|xtb`).","Keep the translate step's parser expectations aligned with the extraction format in one place (shared config)."],"exampleFix":"// before: declared XLIFF 1.2 flow, file is actually XLIFF 2.0\n<xliff version=\"2.0\" xmlns=\"urn:oasis:names:tc:xliff:document:2.0\">...</xliff>\n\n// after: match versions - use XLIFF 1.2\n<xliff version=\"1.2\" xmlns=\"urn:oasis:names:tc:xliff:document:1.2\">...</xliff>\n// (or switch the whole pipeline to --format=xlf2)","handlingStrategy":"validation","validationCode":"// Verify the XML root element matches the expected format before loading\nfunction hasXmlRoot(contents: string, rootName: string): boolean {\n  const match = contents.match(/^\\s*<\\?xml[^>]*\\?>\\s*<(?<root>[a-zA-Z0-9:_.-]+)/);\n  return match?.groups?.root === rootName;\n}\n// XLIFF 1.2 root: 'xliff' with version=\"1.2\"; XLIFF 2.0: 'xliff' version=\"2.0\"; XTB: 'translationbundle'\nif (!hasXmlRoot(contents, 'xliff')) throw new Error(`Unexpected root element in ${filePath}`);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep the extraction format and the translation-file format in one shared config value.","Check the root element's version attribute when files come back from vendors."],"tags":["localize","i18n","xml","xliff","translation-file","root-element"],"backgroundTag":"unsupported-translation-format","analyzedSha":"51cb07e98081ab7e4e84a9e0949266a8e19cca84","analyzedAt":"2026-08-22T07:04:54.531Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}