{"record":{"id":"5940c4f1e86eef42","repo":"iOfficeAI/OfficeCLI","slug":"invalid-crosses-value-value-valid-autozer-5940c4","errorCode":null,"errorMessage":"Invalid 'crosses' value: '{value}'. Valid: autoZero, max, min.","messagePattern":"Invalid 'crosses' value: '(.+?)'\\. Valid: autoZero, max, min\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Core/Chart/ChartHelper.Setter.cs","lineNumber":1921,"sourceCode":"                case \"crosses\":\n                {\n                    var plotArea2 = chart.GetFirstChild<C.PlotArea>();\n                    var valAx = plotArea2?.GetFirstChild<C.ValueAxis>();\n                    if (valAx == null) { unsupported.Add(key); break; }\n                    // Remove only same-type predecessors. The pre-fix code also\n                    // removed C.CrossesAt here, which silently wiped a sibling\n                    // crossesAt value when both keys arrived in the same Set\n                    // call (e.g. crosses + crossesAt + crossBetween together):\n                    // the second branch reset both children and the first\n                    // branch's write disappeared.\n                    // Validate BEFORE mutating — a throw after RemoveAllChildren\n                    // would wipe the prior valid crosses value on bad input.\n                    var crossVal = value.ToLowerInvariant() switch\n                    {\n                        \"max\" => C.CrossesValues.Maximum,\n                        \"min\" => C.CrossesValues.Minimum,\n                        \"autozero\" => C.CrossesValues.AutoZero,\n                        _ => throw new ArgumentException($\"Invalid 'crosses' value: '{value}'. Valid: autoZero, max, min.\")\n                    };\n                    valAx.RemoveAllChildren<C.Crosses>();\n                    // CONSISTENCY(chart/crosses-schema-order): CT_ValAx requires\n                    // crossAx → crosses → crossesAt → crossBetween. Insert\n                    // before whichever later sibling exists.\n                    var newCrosses = new C.Crosses { Val = crossVal };\n                    var crossesAnchor = valAx.GetFirstChild<C.CrossesAt>() as OpenXmlElement\n                        ?? valAx.GetFirstChild<C.CrossBetween>() as OpenXmlElement;\n                    if (crossesAnchor != null) valAx.InsertBefore(newCrosses, crossesAnchor);\n                    else valAx.AppendChild(newCrosses);\n                    break;\n                }\n\n                case \"crossesat\":\n                {\n                    var plotArea2 = chart.GetFirstChild<C.PlotArea>();\n                    var valAx = plotArea2?.GetFirstChild<C.ValueAxis>();\n                    if (valAx == null) { unsupported.Add(key); break; }","sourceCodeStart":1903,"sourceCodeEnd":1939,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Core/Chart/ChartHelper.Setter.cs#L1903-L1939","documentation":"Thrown when 'crosses' is not autoZero, max, or min (OOXML ST_Crosses). The value is validated BEFORE mutating so a bad input does not wipe the prior valid crosses value — a deliberate fix for a bug where a throw after RemoveAllChildren<Crosses> would silently drop a sibling. The new element is inserted in schema order (after crossAx, before crossesAt/crossBetween).","triggerScenarios":"SetChartProperties with { [\"crosses\"] = \"middle\" }, \"atZero\", or a misspelled token on the value axis.","commonSituations":"Mixing 'crosses' with 'crossesAt' vocabulary; typos; case sensitivity (only lowercase is matched).","solutions":["Use autoZero, max, or min.","If you need a numeric crossing point, use 'crossesAt' instead of 'crosses'.","Trim and ToLowerInvariant before passing."],"exampleFix":"// before\nSetChartProperties(part, new() { [\"crosses\"] = \"atZero\" });\n// after\nSetChartProperties(part, new() { [\"crosses\"] = \"autoZero\" });","handlingStrategy":"validation","validationCode":"static readonly HashSet<string> Crosses =\n    new[]{\"autozero\",\"max\",\"min\"}, StringComparer.OrdinalIgnoreCase);\n\nstatic bool IsValidCrosses(string v) =>\n    !string.IsNullOrWhiteSpace(v) && Crosses.Contains(v.Trim().ToLowerInvariant());","typeGuard":"static bool IsKnownCrosses(string v) =>\n    (v?.Trim().ToLowerInvariant()) is \"autozero\" or \"max\" or \"min\";","tryCatchPattern":"try { SetChartProperties(part, props); }\ncatch (ArgumentException ex) when (ex.Message.StartsWith(\"Invalid 'crosses'\"))\n{ /* use crossesAt=<number> for a numeric crossing, or default to autoZero */ }","preventionTips":["Distinguish 'crosses' (enum) from 'crossesAt' (numeric point).","Whitelist crosses to autoZero/max/min.","Trim and lowercase free-text input."],"tags":["ooxml","chart","input-validation","axis","csharp"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}