{"record":{"id":"801d4b0209c7b63c","repo":"iOfficeAI/OfficeCLI","slug":"drawing-group-anchor-xml-must-contain-a-top-level","errorCode":null,"errorMessage":"drawing-group anchor XML must contain a top-level xdr:grpSp.","messagePattern":"drawing-group anchor XML must contain a top-level xdr:grpSp\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Handlers/Excel/ExcelHandler.Add.cs","lineNumber":1139,"sourceCode":"                    ?? throw new ArgumentException(\n                        $\"Sheet not found: {groupSheetName}. drawing-group must be added under a sheet.\");\n                properties ??= new Dictionary<string, string>();\n                var anchorXml = properties.GetValueOrDefault(\"anchor-xml\")\n                    ?? throw new ArgumentException(\n                        \"'anchor-xml' property is required for drawing-group (verbatim xdr anchor XML)\");\n\n                XDR.TwoCellAnchor groupAnchor;\n                try\n                {\n                    groupAnchor = new XDR.TwoCellAnchor(anchorXml);\n                }\n                catch (Exception ex)\n                {\n                    throw new ArgumentException(\n                        $\"drawing-group anchor XML is not a valid xdr:twoCellAnchor: {ex.Message}\", ex);\n                }\n                if (groupAnchor.GetFirstChild<XDR.GroupShape>() == null)\n                    throw new ArgumentException(\n                        \"drawing-group anchor XML must contain a top-level xdr:grpSp.\");\n\n                List<DumpDrawingHyperlinkSpec> groupHyperlinks;\n                try\n                {\n                    groupHyperlinks = DecodeDumpDrawingHyperlinks(\n                        properties.GetValueOrDefault(\"hyperlinks\") ?? \"\");\n                }\n                catch (FormatException ex)\n                {\n                    throw new ArgumentException(\n                        $\"drawing-group 'hyperlinks' carrier is invalid: {ex.Message}\", ex);\n                }\n\n                Modified = true;\n                var groupDrawingsPart = groupWorksheet.DrawingsPart\n                    ?? groupWorksheet.AddNewPart<DrawingsPart>();\n                if (groupDrawingsPart.WorksheetDrawing == null)","sourceCodeStart":1121,"sourceCodeEnd":1157,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Handlers/Excel/ExcelHandler.Add.cs#L1121-L1157","documentation":"The anchor-xml parsed into a valid XDR.TwoCellAnchor, but GetFirstChild<XDR.GroupShape>() returned null — the anchor has no top-level <xdr:grpSp>. The drawing-group carrier exists specifically to round-trip grouped shapes verbatim; an anchor holding only a single pic/sp/cxnSp/graphicFrame is the wrong carrier and should use the matching semantic add (picture/shape/chart) instead.","triggerScenarios":"anchor-xml contains a <xdr:pic>, <xdr:sp>, <xdr:cxnSp>, or <xdr:graphicFrame> but no <xdr:grpSp>; or the group was flattened into leaf shapes during a prior transform.","commonSituations":"Choosing 'drawing-group' for a single shape because it seemed like a catch-all; a dump that flattened groups; an anchor copied from a part that contained an absolute/oneCell anchor wrapping a non-group child.","solutions":["If the object is genuinely a group, supply an anchor whose direct child is <xdr:grpSp>.","If it is a single shape/picture/chart, use the matching part type (--type picture/shape/chart) instead of drawing-group.","Re-dump to obtain the original grouped anchor before any flattening."],"exampleFix":"// before — single shape, no grpSp\nprops[\"anchor-xml\"] = \"<xdr:twoCellAnchor><xdr:sp>...</xdr:sp></xdr:twoCellAnchor>\";\nhandler.AddPart(\"/Sheet1\", \"drawing-group\", props);\n// after — use the semantic shape add, or supply a real grouped anchor\nhandler.AddPart(\"/Sheet1\", \"shape\", props);","handlingStrategy":"validation","validationCode":"var doc = System.Xml.Linq.XDocument.Parse(props[\"anchor-xml\"]);\nvar grp = doc.Descendants()\n    .FirstOrDefault(e => e.Name.LocalName == \"grpSp\"\n        && e.Name.Namespace == XdrNs);\nif (grp == null) { /* wrong carrier — use shape/picture/chart instead */ }","typeGuard":"static bool AnchorHasGroupShape(string xml)\n{ try { return System.Xml.Linq.XDocument.Parse(xml).Descendants()\n    .Any(e => e.Name.LocalName == \"grpSp\"); } catch { return false; } }","tryCatchPattern":"try { handler.AddPart(parent, \"drawing-group\", props); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"top-level xdr:grpSp\"))\n{ /* switch to the matching semantic add (picture/shape/chart) */ }","preventionTips":["Only use drawing-group for genuine grouped shapes.","For single shapes use the picture/shape/chart part types.","Re-dump the original grouped anchor before any flattening."],"tags":["excel","openxml","add-part","drawing-group","structure"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}