{"record":{"id":"2009539a7824c40c","repo":"iOfficeAI/OfficeCLI","slug":"unsupported-criteria-operator-op-valid-equa","errorCode":null,"errorMessage":"Unsupported criteria operator: '{op}'. Valid: equals, notEquals, contains, doesNotContain, beginsWith, endsWith, gt, gte, lt, lte, between, notBetween, top, topPercent, bottom, bottomPercent, blanks, nonBlanks, values, dynamic.","messagePattern":"Unsupported criteria operator: '(.+?)'\\. Valid: equals, notEquals, contains, doesNotContain, beginsWith, endsWith, gt, gte, lt, lte, between, notBetween, top, topPercent, bottom, bottomPercent, blanks, nonBlanks, values, dynamic\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Handlers/Excel/ExcelHandler.Add.Tables.cs","lineNumber":940,"sourceCode":"                            .ToList();\n                        var filters = filterColumn.Filters ?? (filterColumn.Filters = new Filters());\n                        foreach (var v in vals)\n                            filters.AppendChild(new Filter { Val = v });\n                        handledDedicated = true;\n                        break;\n                    }\n                    case \"dynamic\":\n                    {\n                        var dyn = new DynamicFilter\n                        {\n                            Type = new EnumValue<DynamicFilterValues>(new DynamicFilterValues(rawVal))\n                        };\n                        filterColumn.DynamicFilter = dyn;\n                        handledDedicated = true;\n                        break;\n                    }\n                    default:\n                        throw new ArgumentException(\n                            $\"Unsupported criteria operator: '{op}'. Valid: equals, notEquals, contains, doesNotContain, beginsWith, endsWith, gt, gte, lt, lte, between, notBetween, top, topPercent, bottom, bottomPercent, blanks, nonBlanks, values, dynamic.\");\n                }\n            }\n            if (customEntries.Count > 0 && !handledDedicated)\n            {\n                var cf = new CustomFilters();\n                if (customFilterAnd)\n                    cf.And = true;\n                foreach (var (fop, val) in customEntries)\n                    cf.AppendChild(new CustomFilter\n                    {\n                        Operator = fop,\n                        Val = val\n                    });\n                filterColumn.CustomFilters = cf;\n            }\n            autoFilter.AppendChild(filterColumn);\n        }","sourceCodeStart":922,"sourceCodeEnd":958,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Handlers/Excel/ExcelHandler.Add.Tables.cs#L922-L958","documentation":"Thrown by AddAutoFilter's default switch case when the operator in a criteriaN.OP=VAL property key is not one of the recognized names. The operator is extracted by the regex ^criteria(\\d+).([A-Za-z]+)$ and lower-cased, then dispatched; an unrecognized name means the criteria cannot be mapped to an Excel filter element. The message lists every valid operator so the caller can self-correct.","triggerScenarios":"A typo in the operator segment of the key: criteria0.contain=x (missing 's'), criteria0.greaterthan=5 (use 'gt'), criteria0.between2=1,2, or any other key whose OP segment is alphabetic but not in the whitelist.","commonSituations":"Misremembering operator names, mixing camelCase expectations with the actual lowercase names, or relying on an operator the handler never implemented.","solutions":["Use one of the listed operators exactly: equals, notEquals, contains, doesNotContain, beginsWith, endsWith, gt, gte, lt, lte, between, notBetween, top, topPercent, bottom, bottomPercent, blanks, nonBlanks, values, dynamic.","Note the operator is matched case-insensitively, but must match a whitelist entry verbatim otherwise.","If you need a range filter, use between with a 'lo,hi' value."],"exampleFix":"// before\n--prop criteria0.contain=foo\n// after\n--prop criteria0.contains=foo","handlingStrategy":"validation","validationCode":"static readonly HashSet<string> ValidFilterOps = new(StringComparer.OrdinalIgnoreCase)\n{\n    \"equals\",\"notEquals\",\"contains\",\"doesNotContain\",\"beginsWith\",\"endsWith\",\n    \"gt\",\"gte\",\"lt\",\"lte\",\"between\",\"notBetween\",\n    \"top\",\"topPercent\",\"bottom\",\"bottomPercent\",\n    \"blanks\",\"nonBlanks\",\"values\",\"dynamic\"\n};\nstatic bool TryValidateCriteriaOp(string op, out string error)\n{\n    if (ValidFilterOps.Contains(op)) { error = null; return true; }\n    error = $\"Unsupported criteria operator: '{op}'. Valid: \" + string.Join(\", \", ValidFilterOps) + \".\";\n    return false;\n}","typeGuard":"static bool IsValidFilterOp(string op) => ValidFilterOps.Contains(op);","tryCatchPattern":"try { handler.Add(path, \"autofilter\", null, props); }\ncatch (ArgumentException ex) when (ex.Message.StartsWith(\"Unsupported criteria operator\"))\n{ /* surface the whitelist to the caller; likely a typo in criteriaN.OP */ }","preventionTips":["Offer the operator list as an enum or autocomplete set in any UI that builds criteria keys.","Strip stray characters from operator names before constructing the criteriaN.OP key.","Log the failing operator so typos are obvious in error reports."],"tags":["excel","autofilter","validation","unknown-operator"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}