{"record":{"id":"904ae2167a7fa896","repo":"iOfficeAI/OfficeCLI","slug":"autofilter-requires-range-property-e-g-range-a","errorCode":null,"errorMessage":"AutoFilter requires 'range' property (e.g. range=A1:F100)","messagePattern":"AutoFilter requires 'range' property \\(e\\.g\\. range=A1:F100\\)","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Handlers/Excel/ExcelHandler.Add.Tables.cs","lineNumber":740,"sourceCode":"\n        // CONSISTENCY(tracking-rebind): the criteriaN.OP loop below iterates\n        // properties via foreach over the static Dictionary<,> type, which\n        // bypasses TrackingPropertyDictionary's comparer. Mark every\n        // criteriaN.OP key (and `range`) as consumed up-front so they\n        // don't surface as false unsupported_property warnings. Keys that\n        // don't match either pattern fall through to the existing UNSUPPORTED\n        // path naturally.\n        if (properties is OfficeCli.Core.TrackingPropertyDictionary afTracking)\n        {\n            var consumed = properties.Keys\n                .Where(k => string.Equals(k, \"range\", StringComparison.OrdinalIgnoreCase)\n                    || Regex.IsMatch(k, @\"^criteria\\d+\\.[A-Za-z]+$\"))\n                .ToList();\n            afTracking.MarkAllConsumed(consumed);\n        }\n\n        var afRange = properties.GetValueOrDefault(\"range\")\n            ?? throw new ArgumentException(\"AutoFilter requires 'range' property (e.g. range=A1:F100)\");\n\n        // CONSISTENCY(cellref-validate): reject garbage refs (e.g. \"BADREF\")\n        // so Excel doesn't silently open with an invalid <x:autoFilter ref=\"...\">.\n        if (!Regex.IsMatch(afRange.Trim(),\n                @\"^\\$?[A-Z]+\\$?\\d+(?::\\$?[A-Z]+\\$?\\d+)?$\",\n                RegexOptions.IgnoreCase))\n            throw new ArgumentException(\n                $\"Invalid 'range' value: '{afRange}'. Expected a cell range like 'A1:F100' or 'A1'.\");\n        // Canonicalize inverted input (D5:A1) like the rest of the range family.\n        afRange = NormalizeA1Range(afRange);\n\n        // CONSISTENCY(autofilter-table-dup): a Table already owns its own\n        // <autoFilter> internally; layering a sheet-level <autoFilter> over\n        // the same range produces the duplicate that Excel rejects with a\n        // \"found a problem\" repair dialog. Mirror the T4 overlap check\n        // used by AddTable.\n        var afRangeUpper = afRange.ToUpperInvariant();\n        foreach (var existingTdp in afWorksheet.TableDefinitionParts)","sourceCodeStart":722,"sourceCodeEnd":758,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Handlers/Excel/ExcelHandler.Add.Tables.cs#L722-L758","documentation":"Thrown by AddAutoFilter when the properties dictionary contains no \"range\" key. Unlike validation (which accepts sqref/range/ref aliases), AutoFilter accepts only \"range\", so the absence of that single key triggers the error.","triggerScenarios":"Call Add type \"autofilter\" with a properties dictionary that has no \"range\" entry (e.g. only criteria filters, or an empty dict).","commonSituations":"Forgetting the range argument; supplying sqref/ref expecting them to alias (they do not for AutoFilter); building properties dynamically and dropping range.","solutions":["Add properties[\"range\"] = \"A1:F100\" (AutoFilter uses the \"range\" key specifically).","Do not rely on sqref or ref aliases here; only \"range\" is accepted.","Pre-validate that the range key is present before calling."],"exampleFix":"// before\nhandler.Add(\"/Sheet1\", \"autofilter\", null, new() { [\"criteria1.value\"] = \"10\" });\n// after\nhandler.Add(\"/Sheet1\", \"autofilter\", null,\n    new() { [\"range\"] = \"A1:F100\", [\"criteria1.value\"] = \"10\" });","handlingStrategy":"validation","validationCode":"if (!properties.ContainsKey(\"range\"))\n    throw new InvalidOperationException(\"AutoFilter requires the 'range' key\");","typeGuard":"static bool HasAutoFilterRange(Dictionary<string,string> p) => p.ContainsKey(\"range\");","tryCatchPattern":null,"preventionTips":["Remember AutoFilter accepts only 'range', not sqref/ref aliases.","Assert the range key in your builder before calling.","Keep filter criteria keys (criteriaN.*) separate from the required range key."],"tags":["excel","autofilter","required-property","validation"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}