{"record":{"id":"87abd0d9dfd642e3","repo":"iOfficeAI/OfficeCLI","slug":"sheet-not-found-cxsheetname-chartex-must-be-ad","errorCode":null,"errorMessage":"Sheet not found: {cxSheetName}. chartex must be added under a sheet: add-part <file> /<SheetName> --type chartex","messagePattern":"Sheet not found: (.+?)\\. chartex must be added under a sheet: add-part <file> /<SheetName> --type chartex","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Handlers/Excel/ExcelHandler.Add.cs","lineNumber":1207,"sourceCode":"                    .Count(a => a.GetFirstChild<XDR.GroupShape>() != null);\n                return (\"group\", $\"/{groupSheetName}/group[{groupIndex}]\");\n            }\n\n            case \"chartex\":\n            {\n                // Extended (cx:) chart carrier for dump→batch round-trip.\n                // chartEx has no semantic add vocabulary — waterfall/funnel/\n                // sunburst charts are carried VERBATIM: the caller pins the\n                // source rIds so the graphicFrame slice raw-set into the\n                // drawing resolves without rewriting. Mirrors the pptx\n                // SmartArt add-part pattern (pinned rIds + raw payload).\n                // Props: rid (required), xml (base64 cx:chartSpace),\n                // colors-rid/colors-xml, style-rid/style-xml (optional\n                // sub-parts — Excel-authored chartEx always carries both;\n                // dropping them dangles the main part's rels).\n                var cxSheetName = parentPartPath.TrimStart('/');\n                var cxWorksheet = FindWorksheet(cxSheetName)\n                    ?? throw new ArgumentException(\n                        $\"Sheet not found: {cxSheetName}. chartex must be added under a sheet: add-part <file> /<SheetName> --type chartex\");\n                properties ??= new Dictionary<string, string>();\n                var cxRid = properties.GetValueOrDefault(\"rid\")\n                    ?? throw new ArgumentException(\"'rid' property is required for chartex (pinned relationship id)\");\n                var cxXmlB64 = properties.GetValueOrDefault(\"xml\")\n                    ?? throw new ArgumentException(\"'xml' property is required for chartex (base64 cx:chartSpace XML)\");\n\n                var cxDrawingsPart = cxWorksheet.DrawingsPart\n                    ?? cxWorksheet.AddNewPart<DrawingsPart>();\n                if (cxDrawingsPart.WorksheetDrawing == null)\n                {\n                    cxDrawingsPart.WorksheetDrawing =\n                        new DocumentFormat.OpenXml.Drawing.Spreadsheet.WorksheetDrawing();\n                    cxDrawingsPart.WorksheetDrawing.Save();\n                    if (GetSheet(cxWorksheet).GetFirstChild<DocumentFormat.OpenXml.Spreadsheet.Drawing>() == null)\n                    {\n                        var cxDrawRelId = cxWorksheet.GetIdOfPart(cxDrawingsPart);\n                        GetSheet(cxWorksheet).Append(","sourceCodeStart":1189,"sourceCodeEnd":1225,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Handlers/Excel/ExcelHandler.Add.cs#L1189-L1225","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass the hosting sheet name as the parent path (e.g. \"/Sheet1\").","Enumerate sheets and confirm the target exists before the call.","Re-dump from the current workbook to keep sheet names aligned."],"exampleFix":"// before\nhandler.AddPart(\"/xl/charts/chartEx1.xml\", \"chartex\", props);\n// after\nhandler.AddPart(\"/Sheet1\", \"chartex\", props);","handlingStrategy":"validation","validationCode":"var name = parentPartPath.TrimStart('/');\nif (!handler.GetWorksheets().Any(w => w.Name.Equals(name, StringComparison.OrdinalIgnoreCase)))\n    /* fix the parent path before calling AddPart */","typeGuard":"static bool SheetResolves(ExcelHandler h, string parentPartPath) =>\n    h.GetWorksheets().Any(w => w.Name.Equals(\n        parentPartPath.TrimStart('/'), StringComparison.OrdinalIgnoreCase));","tryCatchPattern":"try { handler.AddPart(parentPartPath, \"chartex\", props); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"chartex must be added under a sheet\"))\n{ /* reconcile sheet name, retry with /SheetName */ }","preventionTips":["Pass the host sheet name, not the internal chart part path.","Refresh the dump so sheet names track the live workbook.","Pre-flight the parent path against GetWorksheets()."],"tags":["excel","openxml","add-part","chartex","sheet-lookup"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}