iOfficeAI/OfficeCLI · error · CliException

bare_selector_rejected

bare_selector_rejected

Error message

Bare selector '{path}' is not allowed for '{verb}' — it would match across the whole document.

What it means

Thrown by MutationSelectorGuard.EnsureScoped when a mutating verb (set, remove) is called with a bare, unscoped selector that would match across the entire document. A bare selector like 'cell', 'run', 'shape', or 'cell[value>5]' has no path prefix, so it could rewrite or delete every matching element in the document — one mistaken 'set cell' would change every cell. The guard requires either a '/'-scoped path (e.g. '/Sheet1/cell'), Excel notation (e.g. 'Sheet1!A1'), or a path containing a top-level '/'. The 'query' verb is intentionally NOT guarded.

Source

Thrown at src/officecli/Core/MutationSelectorGuard.cs:49

    /// <summary>
    /// Throw a CliException when <paramref name="path"/> is a bare unscoped
    /// selector on a mutating verb. No-op for `/`-scoped paths, Excel `Sheet!Ref`
    /// notation, and null/empty (handled downstream).
    /// </summary>
    public static void EnsureScoped(string? path, string verb)
    {
        if (string.IsNullOrEmpty(path)) return;
        if (path.StartsWith("/")) return;
        if (ExcelNotation.IsMatch(path)) return;
        // A slash path that lost its leading slash ("Sheet1/row[...]") IS
        // scoped — query already restores the slash and resolves it (see
        // ExcelHandler.QueryDispatch); rejecting it here as "would match
        // across the whole document" was both inconsistent and untrue. A '/'
        // inside a predicate value (row[url~=a/b]) does not count.
        if (SelectorCommaSplit.ContainsTopLevelChar(path, '/')) return;

        throw new CliException(
            $"Bare selector '{path}' is not allowed for '{verb}' — it would match across the whole document.")
        {
            Code = "bare_selector_rejected",
            Suggestion =
                $"Scope the {verb} to a path: '/Sheet1/{path}' / '/slide[1]/{path}' / '/body/p[1]/{path}', " +
                "or use Excel notation 'Sheet1!A1'. Bare selectors stay available on read-only 'query'.",
        };
    }
}

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Scope the selector with a '/'-prefixed path: '/Sheet1/cell[...]', '/slide[1]/shape[...]', or '/body/p[1]/run[...]'.
  2. Use Excel notation 'Sheet1!A1' or 'Sheet1!A1:B5' for cell-range mutations.
  3. Use 'query' instead of 'set'/'remove' if you intended a read-only operation with a bare selector.
  4. Add the sheet, slide, or paragraph scope to the selector before the element type.

Example fix

// before — bare selector rejected
set cell value=0
remove run

// after — scoped selectors
set /Sheet1/cell value=0
remove /body/p[3]/run[1]
// or Excel notation
set Sheet1!A1 value=0
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check that a mutation selector is scoped before calling set/remove
private static bool IsMutationSelectorScoped(string? path)
{
    if (string.IsNullOrEmpty(path)) return true; // null/empty handled downstream
    if (path.StartsWith("/")) return true;
    if (System.Text.RegularExpressions.Regex.IsMatch(path, @"^[^/\[\]]+!")) return true; // Excel notation
    if (path.Contains('/')) return true; // has a path separator
    return false;
}

if (!IsMutationSelectorScoped(selectorPath))
{
    Console.Error.WriteLine($"Bare selector '{selectorPath}' is not allowed for mutation. Scope it: '/Sheet1/{selectorPath}' or 'Sheet1!A1'");
    return;
}

Try / catch

try
{
    handler.Set(path, properties);
}
catch (CliException ex) when (ex.Code == "bare_selector_rejected")
{
    // ex.Suggestion contains guidance — display it and prompt user to scope the selector
    Console.Error.WriteLine(ex.Suggestion);
}

Prevention

When it happens

Trigger: Calling 'set cell value=0' with no path scope. Calling 'remove run' on a Word document. Passing any selector string that: does not start with '/', does not match the Excel notation regex (^[^/\[\]]+!), and does not contain a top-level '/' character. The guard is called from the CLI/MCP/resident/batch agent-facing layer, not from the handler's internal Set/Remove API.

Common situations: An agent or LLM that generates a set/remove command without understanding the scoping requirement. A user who copy-pasted a query selector (which is valid for read-only query) into a set/remove command. A batch script that reuses a discovery selector for a mutation without adding a path prefix.

Related errors


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