iOfficeAI/OfficeCLI · error · ArgumentException

Sheet not found: {oleSheetName}. ole must be added under a s

Error message

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

What it means

Thrown by AddPart for the 'ole' part type — an all-in-one carrier that wires the worksheet's <oleObjects> child, the payload embed rel, the VML anchor shape, and the <legacyDrawing>. OLE anatomy is spread across the worksheet and its VML drawing, so the parent path must resolve to the worksheet that will host the <oleObjects> element.

Source

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

            }

            case "ole":
            {
                // Verbatim OLE carrier for dump→batch round-trip. Mirrors the
                // pptx add-part ole contract (pinned rIds + base64 payloads)
                // but is all-in-one: Excel's OLE anatomy spans the worksheet
                // (<oleObjects> child + embed/icon rels), the VML drawing
                // (anchor shape) and <legacyDrawing>, all of which must stay
                // consistent — so the handler wires everything here instead
                // of leaving XML splicing to a companion raw-set.
                // Props: rid + data (+content-type/extension) = payload part;
                // icon-rid + icon-data (+icon-content-type) = objectPr image;
                // vml-shape = the <v:shape> anchor XML verbatim;
                // object-xml = the <oleObjects> CHILD element verbatim
                // (mc:AlternateContent or bare oleObject, pinned rIds inside).
                var oleSheetName = parentPartPath.TrimStart('/');
                var oleWs = FindWorksheet(oleSheetName)
                    ?? throw new ArgumentException(
                        $"Sheet not found: {oleSheetName}. ole must be added under a sheet: add-part <file> /<SheetName> --type ole");
                properties ??= new Dictionary<string, string>();
                var oleRid = properties.GetValueOrDefault("rid")
                    ?? throw new ArgumentException("'rid' property is required for ole (pinned payload relationship id)");
                var oleDataB64 = properties.GetValueOrDefault("data")
                    ?? throw new ArgumentException("'data' property is required for ole (base64 payload bytes)");
                var oleObjectXml = properties.GetValueOrDefault("object-xml")
                    ?? throw new ArgumentException("'object-xml' property is required for ole (verbatim oleObjects child element)");
                byte[] oleBytes;
                try { oleBytes = Convert.FromBase64String(oleDataB64); }
                catch (FormatException) { throw new ArgumentException("add-part ole: 'data' is not valid base64"); }

                var oleCt = properties.GetValueOrDefault("content-type")
                    ?? "application/vnd.openxmlformats-officedocument.oleObject";
                var oleExt = properties.GetValueOrDefault("extension") ?? ".bin";
                if (!oleExt.StartsWith('.')) oleExt = "." + oleExt;

                // Kind comes from the dump (source part type), because content

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Pass the host sheet display name as the parent path (e.g. "/Sheet1").
  2. List worksheets and confirm the name before the call.
  3. Re-dump against the current file to keep names in sync.
  4. If the original sheet is gone, retarget the OLE to a surviving sheet.

Example fix

// before
handler.AddPart("/xl/embeddings/oleObject1.bin", "ole", props);
// after
handler.AddPart("/Sheet1", "ole", 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, "ole", props); }
catch (ArgumentException ex) when (ex.Message.Contains("ole must be added under a sheet"))
{ /* reconcile sheet name, retry with /SheetName */ }

Prevention

When it happens

Trigger: AddPart(parentPartPath, "ole", ...) where parentPartPath (after TrimStart('/')) does not name an existing worksheet — wrong path, renamed sheet, out-of-range sheet index, or empty.

Common situations: Replaying a dump after the host sheet was renamed/deleted; passing the OLE part path (e.g. "/xl/embeddings/oleObject1.bin") instead of the sheet name; targeting a chart sheet that has no worksheet part.

Related errors


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