iOfficeAI/OfficeCLI · error · ArgumentException

Sheet not found: {cxSheetName}. chartex must be added under

Error message

Sheet not found: {cxSheetName}. chartex must be added under a sheet: add-part <file> /<SheetName> --type chartex

What it means

Thrown by AddPart when handling a 'chartex' part type — the verbatim carrier for extended (cx:) charts (waterfall/funnel/sunburst) that have no semantic add vocabulary. The parent part path must resolve to an existing worksheet, because the chartEx graphicFrame lives in that sheet's DrawingsPart. Uses the same case-insensitive FindWorksheet as other part types.

Source

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

                    .Count(a => a.GetFirstChild<XDR.GroupShape>() != null);
                return ("group", $"/{groupSheetName}/group[{groupIndex}]");
            }

            case "chartex":
            {
                // Extended (cx:) chart carrier for dump→batch round-trip.
                // chartEx has no semantic add vocabulary — waterfall/funnel/
                // sunburst charts are carried VERBATIM: the caller pins the
                // source rIds so the graphicFrame slice raw-set into the
                // drawing resolves without rewriting. Mirrors the pptx
                // SmartArt add-part pattern (pinned rIds + raw payload).
                // Props: rid (required), xml (base64 cx:chartSpace),
                // colors-rid/colors-xml, style-rid/style-xml (optional
                // sub-parts — Excel-authored chartEx always carries both;
                // dropping them dangles the main part's rels).
                var cxSheetName = parentPartPath.TrimStart('/');
                var cxWorksheet = FindWorksheet(cxSheetName)
                    ?? throw new ArgumentException(
                        $"Sheet not found: {cxSheetName}. chartex must be added under a sheet: add-part <file> /<SheetName> --type chartex");
                properties ??= new Dictionary<string, string>();
                var cxRid = properties.GetValueOrDefault("rid")
                    ?? throw new ArgumentException("'rid' property is required for chartex (pinned relationship id)");
                var cxXmlB64 = properties.GetValueOrDefault("xml")
                    ?? throw new ArgumentException("'xml' property is required for chartex (base64 cx:chartSpace XML)");

                var cxDrawingsPart = cxWorksheet.DrawingsPart
                    ?? cxWorksheet.AddNewPart<DrawingsPart>();
                if (cxDrawingsPart.WorksheetDrawing == null)
                {
                    cxDrawingsPart.WorksheetDrawing =
                        new DocumentFormat.OpenXml.Drawing.Spreadsheet.WorksheetDrawing();
                    cxDrawingsPart.WorksheetDrawing.Save();
                    if (GetSheet(cxWorksheet).GetFirstChild<DocumentFormat.OpenXml.Spreadsheet.Drawing>() == null)
                    {
                        var cxDrawRelId = cxWorksheet.GetIdOfPart(cxDrawingsPart);
                        GetSheet(cxWorksheet).Append(

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Pass the hosting sheet name as the parent path (e.g. "/Sheet1").
  2. Enumerate sheets and confirm the target exists before the call.
  3. Re-dump from the current workbook to keep sheet names aligned.

Example fix

// before
handler.AddPart("/xl/charts/chartEx1.xml", "chartex", props);
// after
handler.AddPart("/Sheet1", "chartex", props);
Defensive patterns

Strategy: validation

Validate before calling

var name = parentPartPath.TrimStart('/');
if (!handler.GetWorksheets().Any(w => w.Name.Equals(name, StringComparison.OrdinalIgnoreCase)))
    /* fix the parent path before calling AddPart */

Type guard

static bool SheetResolves(ExcelHandler h, string parentPartPath) =>
    h.GetWorksheets().Any(w => w.Name.Equals(
        parentPartPath.TrimStart('/'), StringComparison.OrdinalIgnoreCase));

Try / catch

try { handler.AddPart(parentPartPath, "chartex", props); }
catch (ArgumentException ex) when (ex.Message.Contains("chartex must be added under a sheet"))
{ /* reconcile sheet name, retry with /SheetName */ }

Prevention

When it happens

Trigger: AddPart(parentPartPath, "chartex", ...) where parentPartPath (after TrimStart('/')) is not a worksheet name — wrong path (e.g. "/xl/charts/chartEx1.xml"), a renamed sheet, an out-of-range sheet[N] index, or empty.

Common situations: Passing the internal chart part path instead of the sheet name; replaying a dump after the target sheet was removed; the chartEx was originally on a sheet that the round-trip renamed.

Related errors


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