iOfficeAI/OfficeCLI · error · ArgumentException

drawing-group anchor XML must contain a top-level xdr:grpSp.

Error message

drawing-group anchor XML must contain a top-level xdr:grpSp.

What it means

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.

Source

Thrown at src/officecli/Handlers/Excel/ExcelHandler.Add.cs:1139

                    ?? throw new ArgumentException(
                        $"Sheet not found: {groupSheetName}. drawing-group must be added under a sheet.");
                properties ??= new Dictionary<string, string>();
                var anchorXml = properties.GetValueOrDefault("anchor-xml")
                    ?? throw new ArgumentException(
                        "'anchor-xml' property is required for drawing-group (verbatim xdr anchor XML)");

                XDR.TwoCellAnchor groupAnchor;
                try
                {
                    groupAnchor = new XDR.TwoCellAnchor(anchorXml);
                }
                catch (Exception ex)
                {
                    throw new ArgumentException(
                        $"drawing-group anchor XML is not a valid xdr:twoCellAnchor: {ex.Message}", ex);
                }
                if (groupAnchor.GetFirstChild<XDR.GroupShape>() == null)
                    throw new ArgumentException(
                        "drawing-group anchor XML must contain a top-level xdr:grpSp.");

                List<DumpDrawingHyperlinkSpec> groupHyperlinks;
                try
                {
                    groupHyperlinks = DecodeDumpDrawingHyperlinks(
                        properties.GetValueOrDefault("hyperlinks") ?? "");
                }
                catch (FormatException ex)
                {
                    throw new ArgumentException(
                        $"drawing-group 'hyperlinks' carrier is invalid: {ex.Message}", ex);
                }

                Modified = true;
                var groupDrawingsPart = groupWorksheet.DrawingsPart
                    ?? groupWorksheet.AddNewPart<DrawingsPart>();
                if (groupDrawingsPart.WorksheetDrawing == null)

View on GitHub (pinned to 1ced45e900)

Solutions

  1. If the object is genuinely a group, supply an anchor whose direct child is <xdr:grpSp>.
  2. If it is a single shape/picture/chart, use the matching part type (--type picture/shape/chart) instead of drawing-group.
  3. Re-dump to obtain the original grouped anchor before any flattening.

Example fix

// before — single shape, no grpSp
props["anchor-xml"] = "<xdr:twoCellAnchor><xdr:sp>...</xdr:sp></xdr:twoCellAnchor>";
handler.AddPart("/Sheet1", "drawing-group", props);
// after — use the semantic shape add, or supply a real grouped anchor
handler.AddPart("/Sheet1", "shape", props);
Defensive patterns

Strategy: validation

Validate before calling

var doc = System.Xml.Linq.XDocument.Parse(props["anchor-xml"]);
var grp = doc.Descendants()
    .FirstOrDefault(e => e.Name.LocalName == "grpSp"
        && e.Name.Namespace == XdrNs);
if (grp == null) { /* wrong carrier — use shape/picture/chart instead */ }

Type guard

static bool AnchorHasGroupShape(string xml)
{ try { return System.Xml.Linq.XDocument.Parse(xml).Descendants()
    .Any(e => e.Name.LocalName == "grpSp"); } catch { return false; } }

Try / catch

try { handler.AddPart(parent, "drawing-group", props); }
catch (ArgumentException ex) when (ex.Message.Contains("top-level xdr:grpSp"))
{ /* switch to the matching semantic add (picture/shape/chart) */ }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13). Data as JSON: /api/errors/801d4b0209c7b63c. Report an issue: GitHub.