{"record":{"id":"653bcb6769c90336","repo":"iOfficeAI/OfficeCLI","slug":"cannot-action-the-document-root-element-node-n","errorCode":null,"errorMessage":"Cannot {action} the document root element <{node.Name.LocalName}>. Target a child element with a more specific --xpath (the root has no parent).","messagePattern":"Cannot (.+?) the document root element <(.+?)>\\. Target a child element with a more specific --xpath \\(the root has no parent\\)\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Core/RawXmlHelper.cs","lineNumber":444,"sourceCode":"        [\"wp\"] = \"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\",\n        [\"mc\"] = \"http://schemas.openxmlformats.org/markup-compatibility/2006\",\n        [\"c\"] = \"http://schemas.openxmlformats.org/drawingml/2006/chart\",\n        [\"xdr\"] = \"http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing\",\n        [\"wps\"] = \"http://schemas.microsoft.com/office/word/2010/wordprocessingShape\",\n        [\"wp14\"] = \"http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing\",\n        [\"v\"] = \"urn:schemas-microsoft-com:vml\",\n    };\n\n    /// <summary>\n    /// Guard actions that need a parent element. An XPath like <c>//*</c> also\n    /// matches the document root, whose <see cref=\"XElement.Parent\"/> is null;\n    /// calling Remove()/AddBeforeSelf()/AddAfterSelf() on it threw a raw\n    /// NullReferenceException. Surface a clear, actionable error instead.\n    /// </summary>\n    private static void RequireParent(XElement node, string action)\n    {\n        if (node.Parent == null)\n            throw new ArgumentException(\n                $\"Cannot {action} the document root element <{node.Name.LocalName}>. \" +\n                $\"Target a child element with a more specific --xpath (the root has no parent).\");\n    }\n\n    private static List<XElement> ParseFragment(string xml, XDocument contextDoc)\n    {\n        // Collect namespace declarations from the context document\n        var nsDict = new Dictionary<string, string>(CommonNamespaces);\n        string? defaultNs = null;\n\n        if (contextDoc.Root != null)\n        {\n            // Inherit the default namespace from the document root so that\n            // unprefixed elements (e.g. <mergeCells>) are parsed into the\n            // correct namespace (e.g. spreadsheetml) instead of empty namespace.\n            var rootNsName = contextDoc.Root.Name.NamespaceName;\n            if (!string.IsNullOrEmpty(rootNsName))\n                defaultNs = rootNsName;","sourceCodeStart":426,"sourceCodeEnd":462,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Core/RawXmlHelper.cs#L426-L462","documentation":"Thrown by RequireParent when a raw-XML mutation action (remove, insertbefore, insertafter) targets the document root element, whose XElement.Parent is null. The guard exists because calling Remove()/AddBeforeSelf()/AddAfterSelf() on a parentless node previously surfaced as an opaque NullReferenceException. It converts that into an actionable message naming the root element and asking for a more specific --xpath.","triggerScenarios":"Invoking raw-xml remove/insertbefore/insertafter with an --xpath that resolves to the document root — e.g. '//*' (matches everything including root), '/*', '/w:document', or '/p:sld'. RequireParent is called at the remove (RawXmlHelper.cs:226), insertbefore (line 184), and insertafter (line 199) call sites.","commonSituations":"A developer uses a broad XPath like '//*' intending to match all child elements, not realizing it also matches the document root. Or an XPath like '/w:document//w:p' is correct but '/w:document' alone targets root. Also happens when an XPath predicate resolves to a single root node.","solutions":["Tighten --xpath to target child elements only, e.g. '//w:p' instead of '//*', or '//w:body/w:p' for Word.","Add a predicate that excludes the root: '//*[parent::*]' matches only nodes that have a parent.","If you genuinely need to operate on the root, use a different action (the root cannot be removed or given a sibling — modify its children instead)."],"exampleFix":"// before\nraw remove --xpath \"//*\"\n// after\nraw remove --xpath \"//*[parent::*]\"","handlingStrategy":"validation","validationCode":"// Before remove/insert on an XElement from XPath, confirm it has a parent\nforeach (var node in doc.XPathSelectElements(xpath))\n{\n    if (node.Parent == null)\n        throw new InvalidOperationException($\"XPath matched the document root <{node.Name.LocalName}>; refine --xpath to a child element.\");\n    node.Remove();\n}","typeGuard":"// C# has no runtime type-guard; narrow by property instead\nstatic bool IsMutableChild(XElement e) => e.Parent != null;","tryCatchPattern":"try { /* raw remove/insert with xpath */ }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"document root element\"))\n{ /* surface to user: refine --xpath to target a child element */ }","preventionTips":["Avoid '//*' for mutation ops; prefer a typed child path like '//w:p'.","Add a '[parent::*]' predicate to exclude the root from any broad XPath.","Validate the selected node set contains no parentless nodes before mutating."],"tags":["raw-xml","xpath","argument","ooxml"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}