iOfficeAI/OfficeCLI · warning · ArgumentException

docProps is a singleton; use /docProps or / (no index).

Error message

docProps is a singleton; use /docProps or / (no index).

What it means

Thrown by ExcelHandler.Get when the first path segment is /docProps[N]. docProps (core/extended document properties) is a document-level singleton part with exactly one instance per workbook, so an index is meaningless. The guard redirects the caller to the canonical /docProps (or /) route instead of treating 'docProps[N]' as a sheet name, which would otherwise raise a misleading SheetNotFoundException. Mirrors the /workbook[N] singleton redirect.

Source

Thrown at src/officecli/Handlers/Excel/ExcelHandler.Query.cs:230

                nrNode.Format["comment"] = dn.Comment.Value;
            if (dn.Function?.Value == true)
                nrNode.Format["volatile"] = true;

            return nrNode;
        }

        // Parse path: /SheetName or /SheetName/A1 or /SheetName/A1:D10
        var segments = path.TrimStart('/').Split('/', 2);
        var sheetNameFromPath = segments[0];
        // workbook is a singleton at the document root — reject an indexed
        // /workbook[N] with a redirect rather than treating "workbook[N]" as a
        // sheet name (which fires a misleading SheetNotFoundException). Mirrors
        // the pptx notes[N]/theme[N] and docx watermark[N] redirects.
        if (Regex.IsMatch(sheetNameFromPath, @"^workbook\[\d+\]$", RegexOptions.IgnoreCase))
            throw new ArgumentException("workbook is a singleton; use /workbook or / (no index).");
        // docProps is a document-level part, not a sheet — same redirect class.
        if (Regex.IsMatch(sheetNameFromPath, @"^docProps\[\d+\]$", RegexOptions.IgnoreCase))
            throw new ArgumentException("docProps is a singleton; use /docProps or / (no index).");
        var worksheet = FindWorksheet(sheetNameFromPath);
        if (worksheet == null)
            throw SheetNotFoundException(sheetNameFromPath);
        // CONSISTENCY(path-stability): if the path used sheet[N] / sheet[last()],
        // rebuild the canonical path with the resolved sheet name so the returned
        // node.Path reflects the actual sheet (matches Word's last() echo behavior).
        var resolvedSheetName = ResolveSheetName(sheetNameFromPath);
        if (!resolvedSheetName.Equals(sheetNameFromPath, StringComparison.Ordinal))
        {
            sheetNameFromPath = resolvedSheetName;
            path = segments.Length == 1 ? $"/{resolvedSheetName}" : $"/{resolvedSheetName}/{segments[1]}";
        }

        var data = GetSheet(worksheet).GetFirstChild<SheetData>();
        if (data == null)
            return new DocumentNode { Path = path, Type = "sheet", Preview = "(empty)" };

        if (segments.Length == 1)

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Drop the index: call handler.Get("/docProps") (or Get("/") for the whole workbook).
  2. Special-case singleton root parts (docProps, workbook) in any generic path builder so they emit no index.
  3. Pre-validate the path: regex ^docProps\[\d+\]$ => rewrite to /docProps before calling Get.

Example fix

// before
var props = handler.Get("/docProps[1]"); // throws

// after
var props = handler.Get("/docProps");
Defensive patterns

Strategy: validation

Validate before calling

// docProps/workbook are singletons — strip any [N] before Get
var head = path.TrimStart('/').Split('/', 2)[0];
if (Regex.IsMatch(head, @"^(?:workbook|docProps)\[\d+$", RegexOptions.IgnoreCase))
    path = "/" + head.Split('[')[0];
return handler.Get(path);

Type guard

static bool IsIndexedSingleton(string path) =>
    Regex.IsMatch(path.TrimStart('/').Split('/', 2)[0],
        @"^(?:workbook|docProps)\[\d+\]$", RegexOptions.IgnoreCase);

Prevention

When it happens

Trigger: Calling handler.Get("/docProps[1]"), Get("/docProps[2]"), or any /docProps[N] on an opened .xlsx. Happens when a generic path builder appends [1] to every top-level node it discovers under /.

Common situations: Code that synthesizes element paths as name[index] for all root nodes. Copy-pasting a /sheet[1] or /chart[1] pattern onto document-level parts. Misreading the tree where docProps sits at the document root, not under a sheet.

Related errors


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