iOfficeAI/OfficeCLI · error · ArgumentException

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

Error message

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

What it means

Thrown by ExcelHandler.Get when the first path segment matches /workbook[N] (an indexed form). The workbook is a singleton at the document root, so an index is meaningless; the guard redirects the caller to /workbook or / rather than treating 'workbook[N]' as a sheet name (which would fire a misleading SheetNotFoundException). Mirrors the same redirect class used for docProps[N], notes[N], theme[N].

Source

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

                nrNode.Format["scope"] = "workbook";
            }
            if (!string.IsNullOrEmpty(dn.Comment?.Value))
                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)

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Address the workbook root without an index: use /workbook or simply /.
  2. In generic enumerators, special-case the singleton roots (workbook, docProps) before emitting an indexed path.

Example fix

// before
get /workbook[0]

// after
get /
// or
get /workbook
Defensive patterns

Strategy: validation

Validate before calling

if (Regex.IsMatch(path.TrimStart('/').Split('/',2)[0], @"^workbook\[\d+\]$", RegexOptions.IgnoreCase))
    path = "/workbook";   // normalize indexed singleton to its canonical root

Prevention

When it happens

Trigger: Issuing get /workbook[0], get /workbook[1], or programmatically calling Get("/workbook[2]").

Common situations: An agent/loop that synthesizes indexed paths by template ('/{type}[{i}]'); a generic enumerator that assumes every top-level node is indexable; copy-paste of a sheet[N] pattern onto the workbook root.

Related errors


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