{"record":{"id":"5bf4a5fe6fc5eb67","repo":"iOfficeAI/OfficeCLI","slug":"not-found-5bf4a5","errorCode":"not_found","errorMessage":"No elements matched selector: {path}","messagePattern":"No elements matched selector: (.+?)","errorType":"exception","errorClass":"Core.CliException","httpStatus":null,"severity":"error","filePath":"src/officecli/Handlers/Excel/ExcelHandler.Remove.cs","lineNumber":49,"sourceCode":"        // each match, mirroring ExcelHandler.Set's selector branch. Row removals\n        // are TRUE shift-deletes (rows below shift up — see \"row[N] — true shift\n        // delete\"), so multiple matched rows MUST be removed in DESCENDING row\n        // order: deleting /Sheet/row[2] first renumbers the old row[4] to row[3]\n        // and the next delete would hit the wrong row. Non-row targets carry\n        // index 0 and keep a stable relative order.\n        if (!string.IsNullOrEmpty(path)\n            && (!path.StartsWith(\"/\") || Core.AttributeFilter.IsContentFilterPath(path)))\n        {\n            // Narrow via the shared engine (same as Set / query): pure-AND on the\n            // legacy path, `or` selectors queried bracket-stripped then narrowed by\n            // the boolean expression tree. The IsContentFilterPath arm routes a\n            // `/`-scoped content filter (`/Sheet1/cell[value>5 or value<1]`) here\n            // too, matching the Set dispatch — query, set and remove now agree on\n            // every selector shape.\n            var (targets, _) = Core.AttributeFilter.FilterSelector(path, Query, ResolveCellAttributeAlias);\n            if (targets.Count == 0)\n                // Empty selector result is not_found, not a crash — see Set.cs.\n                throw new Core.CliException($\"No elements matched selector: {path}\") { Code = \"not_found\" };\n\n            var ordered = targets.OrderByDescending(t => ExtractRowIndexForRemoval(t.Path)).ToList();\n            string? lastWarning = null;\n            foreach (var target in ordered)\n            {\n                var w = Remove(target.Path, properties);\n                if (w != null) lastWarning = w;\n            }\n            var summary = $\"{ordered.Count} element(s) removed by selector '{path}'\";\n            return lastWarning != null ? $\"{summary}; {lastWarning}\" : summary;\n        }\n\n        path = NormalizeExcelPath(path);\n        path = ResolveSheetIndexInPath(path);\n        var segments = path.TrimStart('/').Split('/', 2);\n        var sheetName = segments[0];\n\n        // Handle /namedrange[N] or /namedrange[Name] before sheet lookup","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Handlers/Excel/ExcelHandler.Remove.cs#L31-L67","documentation":"Thrown (code not_found) by the selector branch of Remove when FilterSelector(path, ...) returns zero targets. This branch handles selector paths (not starting with '/') and content-filter paths; an empty match set is reported as not_found rather than a silent no-op, mirroring the Set dispatch so query/set/remove agree on selector behavior.","triggerScenarios":"remove row[col.missing=foo] where no rows match; remove /Sheet1/cell[value>999] with no such cells; any selector that matches nothing.","commonSituations":"Filtering on a non-existent column/value; race where data changed between query and remove; case mismatch in values; selector typos.","solutions":["Run the same selector as a get/query first to confirm it matches before calling remove.","Correct the selector (column name, value, operator) against the actual sheet contents.","Treat not_found as benign in your caller if an empty match is acceptable (catch code 'not_found')."],"exampleFix":"// before\nremove row[col.mising=foo]   // typo: 'mising'\n// after\nget row[col.missing=foo]      // verify matches exist\nremove row[col.missing=foo]","handlingStrategy":"try-catch","validationCode":"# dry-run the selector as a query first\nmatches = doc.query('row[col.missing=foo]')\nif not matches:\n    print('selector matches nothing — nothing to remove')\nelse:\n    doc.remove('row[col.missing=foo]')","typeGuard":"null","tryCatchPattern":"try:\n    doc.remove('row[col.missing=foo]')\nexcept officecli.OfficeCliError as e:\n    if getattr(e, 'code', None) == 'not_found' or 'No elements matched' in str(e):\n        pass  # empty match is benign for our use case\n    else:\n        raise","preventionTips":["Run the selector as a query first to confirm matches before removing.","Verify column names and values against the actual sheet.","Treat 'not_found' as benign if an empty match is acceptable."],"tags":["excel","remove","selector","not-found","query"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}