{"record":{"id":"d649733a11e04ac9","repo":"iOfficeAI/OfficeCLI","slug":"cellis-operator-opstr-requires-value2-proper","errorCode":null,"errorMessage":"cellIs operator '{opStr}' requires 'value2' property (e.g. value=10 value2=50).","messagePattern":"cellIs operator '(.+?)' requires 'value2' property \\(e\\.g\\. value=10 value2=50\\)\\.","errorType":"validation","errorClass":"System.ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Handlers/Excel/ExcelHandler.Add.Cf.cs","lineNumber":555,"sourceCode":"            \"between\" => ConditionalFormattingOperatorValues.Between,\n            \"notbetween\" => ConditionalFormattingOperatorValues.NotBetween,\n            _ => throw new ArgumentException(\n                $\"Unsupported cellIs operator '{opStr}'. Valid: greaterThan, lessThan, greaterThanOrEqual, lessThanOrEqual, equal, notEqual, between, notBetween.\")\n        };\n\n        var primary = properties.GetValueOrDefault(\"value\")\n            ?? properties.GetValueOrDefault(\"formula\")\n            ?? properties.GetValueOrDefault(\"value1\")\n            ?? throw new ArgumentException(\"cellIs conditional formatting requires 'value' property (e.g. value=50).\");\n        var secondary = properties.GetValueOrDefault(\"value2\")\n            ?? properties.GetValueOrDefault(\"formula2\")\n            ?? properties.GetValueOrDefault(\"maxvalue\");\n\n        if ((opVal == ConditionalFormattingOperatorValues.Between\n             || opVal == ConditionalFormattingOperatorValues.NotBetween)\n            && secondary == null)\n        {\n            throw new ArgumentException(\n                $\"cellIs operator '{opStr}' requires 'value2' property (e.g. value=10 value2=50).\");\n        }\n\n        // cellIs value/value2 land in <x:formula> (A1-only). Reject R1C1-style\n        // refs so the file doesn't silently become one Excel refuses to open.\n        ValidateNoR1C1Reference(primary);\n        if (secondary != null) ValidateNoR1C1Reference(secondary);\n\n        // Build DifferentialFormat (dxf)\n        var cisDxf = new DifferentialFormat();\n        if (properties.TryGetValue(\"font.color\", out var cisFontColor))\n        {\n            var normalizedFontColor = ParseHelpers.NormalizeArgbColor(cisFontColor);\n            cisDxf.Append(new Font(new DocumentFormat.OpenXml.Spreadsheet.Color { Rgb = normalizedFontColor }));\n        }\n        if (properties.TryGetValue(\"font.bold\", out var cisFontBold) && IsTruthy(cisFontBold))\n        {\n            var existingFont = cisDxf.GetFirstChild<Font>();","sourceCodeStart":537,"sourceCodeEnd":573,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Handlers/Excel/ExcelHandler.Add.Cf.cs#L537-L573","documentation":"Thrown by AddCellIs when the operator is 'between' or 'notBetween' but no secondary operand is supplied. A between/notBetween comparison is binary (lower and upper bound), so the rule needs two <x:formula> children. The secondary value is read from 'value2', 'formula2', or 'maxvalue'.","triggerScenarios":"Calling Add with type=cellis operator=between (or notBetween), a primary value, but none of value2/formula2/maxvalue. Example: add /Sheet1/A1 cellis operator=between value=10 (missing upper bound).","commonSituations":"User assumes between defaults to an implicit upper bound; forgot the second property; used 'max=' instead of the accepted 'maxvalue=' alias.","solutions":["Supply the upper bound via value2, formula2, or maxvalue (e.g. value=10 value2=50).","Switch to a unary operator (greaterThan, lessThan, equal, etc.) if only one bound is intended.","Double-check the alias spelling — 'max=' is not accepted, use 'maxvalue='."],"exampleFix":"// before: missing upper bound\nadd /Sheet1/A1:A10 cellis operator=between value=10\n// after\nadd /Sheet1/A1:A10 cellis operator=between value=10 value2=50","handlingStrategy":"validation","validationCode":"var op = (properties.GetValueOrDefault(\"operator\") ?? \"greaterThan\").Trim().ToLowerInvariant();\nvar needsSecond = op is \"between\" or \"notbetween\";\nvar hasSecond = properties.ContainsKey(\"value2\") || properties.ContainsKey(\"formula2\") || properties.ContainsKey(\"maxvalue\");\nif (needsSecond && !hasSecond)\n    throw new ArgumentException($\"operator '{op}' requires value2/formula2/maxvalue.\");","typeGuard":"static bool CellIsHasRequiredOperands(IReadOnlyDictionary<string,string> p)\n{\n    var op = (p.GetValueOrDefault(\"operator\") ?? \"greaterThan\").Trim().ToLowerInvariant();\n    if (op is not (\"between\" or \"notbetween\")) return true;\n    return p.ContainsKey(\"value2\") || p.ContainsKey(\"formula2\") || p.ContainsKey(\"maxvalue\");\n}","tryCatchPattern":"try { return Add(path, \"cellis\", pos, props); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"requires 'value2'\"))\n{ /* prompt for upper bound, retry */ throw; }","preventionTips":["For between/notBetween, always supply value2 (or formula2/maxvalue).","Remember 'max=' is not an alias — use 'maxvalue='.","Switch to a unary operator if only one bound is needed."],"tags":["excel","conditional-formatting","cellis","required-property","conditional-validation"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}