iOfficeAI/OfficeCLI · error · ArgumentException
'{part}' is a predicate, but this verb navigates by position
Error message
'{part}' is a predicate, but this verb navigates by position and expects a numeric index (e.g. {part[..part.IndexOf('[')]}[2]). Predicates work on 'query' (read) and 'set'/'remove' (mutate matched elements). What it means
Thrown by the GenericXmlQuery path parser when the bracket content is a predicate (content filter) rather than a numeric index, but the verb in use navigates by position only. 'get' is one-node-by-path by contract; predicates run on the selector engine used by 'query' (read) and 'set'/'remove' (mutate). The message directs the caller to the verbs that support predicates.
Source
Thrown at src/officecli/Core/GenericXmlQuery.cs:259
{
if (string.IsNullOrEmpty(part)) continue;
var bracketIdx = part.IndexOf('[');
if (bracketIdx >= 0)
{
// BUG-R36-01 fix: when ']' is missing (e.g. "slide[") the expression
// part[(bracketIdx+1)..^1] produces a negative-length range crash.
// Detect and reject unclosed brackets with a clean ArgumentException.
var closingIdx = part.IndexOf(']', bracketIdx + 1);
if (closingIdx < 0)
throw new ArgumentException($"Malformed path segment '{part}'. Bracket '[' is not closed. Expected format: name[index] or name[@attr=value].");
var name = PathAliases.Resolve(part[..bracketIdx]);
var indexStr = part[(bracketIdx + 1)..^1];
if (!int.TryParse(indexStr, out var idx))
// A predicate in the index slot (row[Score>0], row[not(V)])
// means the caller reached the single-node path navigator
// with a FILTER. get is one-node-by-path by contract;
// point at the verbs that run the selector engine.
throw new ArgumentException(AttributeFilter.IsContentFilterPath($"[{indexStr}]")
? $"'{part}' is a predicate, but this verb navigates by position and expects a numeric index (e.g. {part[..part.IndexOf('[')]}[2]). Predicates work on 'query' (read) and 'set'/'remove' (mutate matched elements)."
: $"Invalid path index '{indexStr}' in segment '{part}'. Expected a numeric index.");
if (idx < 1)
throw new ArgumentException($"Invalid path index '{idx}' in segment '{part}'. Index must be >= 1.");
segments.Add((name, idx));
}
else
{
segments.Add((PathAliases.Resolve(part), null));
}
}
return segments;
}
/// <summary>
/// Navigate an OpenXML element tree by path segments (localName + optional 1-based index).
/// Returns null if any segment cannot be resolved.
/// </summary>View on GitHub (pinned to 1ced45e900)
Solutions
- Switch to the 'query' verb for read filtering, or 'set'/'remove' for mutating matched elements.
- For positional navigation with get, use a numeric index (e.g. row[2]).
- Confirm whether you need a single node (get) or a filtered set (query).
Example fix
// before Get(xml, "rows/row[Score>0]"); // get cannot predicate // after Query(xml, "rows/row[Score>0]"); // query runs the selector engine
Defensive patterns
Strategy: validation
Validate before calling
static string ChooseVerbForSegment(string segment) =>
segment.Contains('[') && AttributeFilter.IsContentFilterPath(segment[segment.IndexOf('[')..])
? "query" : "get"; Prevention
- Remember get navigates by position; query/set/remove run predicates.
- Use numeric indices with get, predicates with query.
When it happens
Trigger: Calling get with a segment like 'row[Score>0]' or 'row[not(V)]' where the bracket content is recognized by AttributeFilter.IsContentFilterPath as a predicate rather than a number.
Common situations: Using get expecting it to filter; confusing positional navigation (row[2]) with predicate filtering (row[Score>0]); porting a query-style path to the get verb.
Related errors
- Malformed path segment '{part}'. Bracket '[' is not closed.
- Invalid path index '{indexStr}' in segment '{part}'. Expecte
- Invalid path index '{idx}' in segment '{part}'. Index must b
- 127
- 'remove' command requires 'path' field. Example: {"command":
AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13).
Data as JSON: /api/errors/00661ad8edc51797.
Report an issue: GitHub.