iOfficeAI/OfficeCLI · error · CliException

invalid_selector

invalid_selector

Error message

Malformed selector: unclosed bracket in "{selector}"

What it means

Thrown by AttributeFilter.Parse when the number of '[' characters in the selector does not equal the number of ']' characters. Attribute filters live inside brackets ([key=value], [key]), so an unbalanced bracket cannot form a valid filter. This is the simple (flat) parser used for single-condition selectors. It is a CliException with Code=invalid_selector.

Source

Thrown at src/officecli/Core/AttributeFilter.cs:105

        return blocks;
    }

    // Regex: numeric positional index [N] only (used for reverse-doc-order keys).
    private static readonly Regex BracketIndexRegex = new(
        @"\[(\d+)\]",
        RegexOptions.Compiled);

    /// <summary>
    /// Parse all [key op value] conditions from a selector string.
    /// Throws CliException for malformed selectors.
    /// </summary>
    public static List<Condition> Parse(string selector)
    {
        // Check for unclosed brackets
        var openCount = selector.Count(c => c == '[');
        var closeCount = selector.Count(c => c == ']');
        if (openCount != closeCount)
            throw new CliException($"Malformed selector: unclosed bracket in \"{selector}\"")
            {
                Code = "invalid_selector",
                Suggestion = "Ensure every '[' has a matching ']'. Example: paragraph[style=Heading 1]"
            };

        var conditions = new List<Condition>();
        var matchedSpans = new HashSet<(int Start, int End)>();

        foreach (Match m in AttrRegex.Matches(selector))
        {
            var key = m.Groups[1].Value;
            var opStr = m.Groups[2].Value.Replace("\\", "");
            var rawVal = m.Groups[3].Value;
            // CONSISTENCY(find-regex): preserve quotes when the value is the
            // `r"..."` / `r'...'` regex form so MatchOne can detect it. Trim
            // would otherwise eat the surrounding quote that marks the prefix.
            var isRegexForm = rawVal.Length >= 3 && rawVal[0] == 'r'
                && (rawVal[1] == '"' || rawVal[1] == '\'');

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Count brackets and add the missing ']' so every '[' has a matching ']'.
  2. If a value contains a literal bracket, wrap it in quotes ("...") or use the r"..." regex form so the quote-aware parser treats it as text.
  3. Prefer the boolean-expression syntax (e.g. cell[a and b]) which is bracket-aware.

Example fix

# before
query 'shape[fill=#FF0000'
# after
query 'shape[fill=#FF0000]'
Defensive patterns

Strategy: validation

Validate before calling

static void EnsureBalancedBrackets(string selector)
{
    var open = selector.Count(c => c == '[');
    var close = selector.Count(c => c == ']');
    if (open != close)
        throw new ArgumentException($"Selector has {open} '[' and {close} ']'; they must balance.");
}

Type guard

static bool HasBalancedBrackets(string s) =>
    s.Count(c => c == '[') == s.Count(c => c == ']');

Try / catch

try { conditions = AttributeFilter.Parse(selector); }
catch (CliException ex) when (ex.Code == "invalid_selector" && ex.Message.Contains("unclosed bracket"))
{ /* balance the selector and retry */ }

Prevention

When it happens

Trigger: A selector like 'shape[fill=#FF0000' (missing closing bracket), or 'shape[fill=#FF0000][size' (second bracket unclosed). A path copied from output where a trailing ']' was trimmed.

Common situations: A user edits a working selector and deletes a ']'. An agent truncates a long path string. A value containing a literal ']' that the simple counter misreads (use the boolean-expression parser / quote the value instead).

Understand the failure class

Related errors


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