{"record":{"id":"00661ad8edc51797","repo":"iOfficeAI/OfficeCLI","slug":"part-is-a-predicate-but-this-verb-navigates-b","errorCode":null,"errorMessage":"'{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).","messagePattern":"'(.+?)' is a predicate, but this verb navigates by position and expects a numeric index \\(e\\.g\\. (.+?)\\[2\\]\\)\\. Predicates work on 'query' \\(read\\) and 'set'/'remove' \\(mutate matched elements\\)\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Core/GenericXmlQuery.cs","lineNumber":259,"sourceCode":"        {\n            if (string.IsNullOrEmpty(part)) continue;\n            var bracketIdx = part.IndexOf('[');\n            if (bracketIdx >= 0)\n            {\n                // BUG-R36-01 fix: when ']' is missing (e.g. \"slide[\") the expression\n                // part[(bracketIdx+1)..^1] produces a negative-length range crash.\n                // Detect and reject unclosed brackets with a clean ArgumentException.\n                var closingIdx = part.IndexOf(']', bracketIdx + 1);\n                if (closingIdx < 0)\n                    throw new ArgumentException($\"Malformed path segment '{part}'. Bracket '[' is not closed. Expected format: name[index] or name[@attr=value].\");\n                var name = PathAliases.Resolve(part[..bracketIdx]);\n                var indexStr = part[(bracketIdx + 1)..^1];\n                if (!int.TryParse(indexStr, out var idx))\n                    // A predicate in the index slot (row[Score>0], row[not(V)])\n                    // means the caller reached the single-node path navigator\n                    // with a FILTER. get is one-node-by-path by contract;\n                    // point at the verbs that run the selector engine.\n                    throw new ArgumentException(AttributeFilter.IsContentFilterPath($\"[{indexStr}]\")\n                        ? $\"'{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).\"\n                        : $\"Invalid path index '{indexStr}' in segment '{part}'. Expected a numeric index.\");\n                if (idx < 1)\n                    throw new ArgumentException($\"Invalid path index '{idx}' in segment '{part}'. Index must be >= 1.\");\n                segments.Add((name, idx));\n            }\n            else\n            {\n                segments.Add((PathAliases.Resolve(part), null));\n            }\n        }\n        return segments;\n    }\n\n    /// <summary>\n    /// Navigate an OpenXML element tree by path segments (localName + optional 1-based index).\n    /// Returns null if any segment cannot be resolved.\n    /// </summary>","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Core/GenericXmlQuery.cs#L241-L277","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":"// before\nGet(xml, \"rows/row[Score>0]\"); // get cannot predicate\n// after\nQuery(xml, \"rows/row[Score>0]\"); // query runs the selector engine","handlingStrategy":"validation","validationCode":"static string ChooseVerbForSegment(string segment) =>\n    segment.Contains('[') && AttributeFilter.IsContentFilterPath(segment[segment.IndexOf('[')..])\n        ? \"query\" : \"get\";","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Remember get navigates by position; query/set/remove run predicates.","Use numeric indices with get, predicates with query."],"tags":["xml","path","predicate","api-misuse"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}