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
- Scope the selector with a '/'-prefixed path: '/Sheet1/cell[...]', '/slide[1]/shape[...]', or '/body/p[1]/run[...]'.
- Use Excel notation 'Sheet1!A1' or 'Sheet1!A1:B5' for cell-range mutations.
- Use 'query' instead of 'set'/'remove' if you intended a read-only operation with a bare selector.
- 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
- Always prefix mutation selectors with a '/'-scoped path: '/Sheet1/cell', '/slide[1]/shape', '/body/p[1]/run'.
- For Excel mutations, use 'Sheet!Ref' notation: 'Sheet1!A1:B5'.
- Use 'query' (not set/remove) for bare selector discovery — it is not guarded.
- In agent/LLM pipelines, validate that mutation selectors contain a path scope before submitting.
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.