{"record":{"id":"aabf1567bd652e3c","repo":"iOfficeAI/OfficeCLI","slug":"invalid-propertyname-value-value-expected-aabf15","errorCode":null,"errorMessage":"Invalid '{propertyName}' value '{value}'. Expected a finite number.","messagePattern":"Invalid '(.+?)' value '(.+?)'\\. Expected a finite number\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Core/ParseHelpers.cs","lineNumber":489,"sourceCode":"        // inherently position-ordered, and lets a future text-mutating path process\n        // ranges back-to-front (descending) so earlier offsets stay valid — the same\n        // reason ProcessFindInParagraph iterates its matches in reverse.\n        result.Sort((a, b) => a.Start != b.Start ? a.Start.CompareTo(b.Start) : a.End.CompareTo(b.End));\n        return result;\n    }\n\n    /// <summary>\n    /// Safely parse a string as double, throwing ArgumentException with a clear message on failure.\n    /// </summary>\n    public static double SafeParseDouble(string value, string propertyName)\n    {\n        // NumberStyles.Float (NOT the default Float|AllowThousands) — matches every\n        // other numeric parser in this file. AllowThousands would silently strip a\n        // decimal comma (\"45,5\" -> 455), producing a 10x/1000x-wrong value from a\n        // comma-decimal-locale input instead of rejecting it.\n        if (!double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result)\n            || double.IsNaN(result) || double.IsInfinity(result))\n            throw new ArgumentException($\"Invalid '{propertyName}' value '{value}'. Expected a finite number.\");\n        return result;\n    }\n\n    /// <summary>\n    /// Parse a rotation value in degrees. Rejects non-finite, NaN, and values\n    /// outside [-3600, 3600] degrees (ten full revolutions either direction).\n    /// OOXML stores rotation as ST_Angle (60000ths of a degree) which fits in\n    /// an Int32 up to ~±35790°, but values above ~±3600° are functionally\n    /// indistinguishable from their modulo-360 reduction while opening the\n    /// door to silent overflow on the (deg * 60000) multiply. The clamp is\n    /// applied uniformly across pptx shape/group/connector add+set sites.\n    /// </summary>\n    public static double SafeParseRotationDegrees(string value, string propertyName)\n    {\n        var deg = SafeParseDouble(value, propertyName);\n        if (deg < -3600 || deg > 3600)\n            throw new ArgumentException($\"Invalid '{propertyName}' value '{value}': degrees must be in [-3600, 3600].\");\n        return deg;","sourceCodeStart":471,"sourceCodeEnd":507,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Core/ParseHelpers.cs#L471-L507","documentation":"Thrown by ParseHelpers.SafeParseDouble when the value is not a finite number. Parsing uses NumberStyles.Float (NOT the default Float|AllowThousands), so it deliberately rejects thousands separators — this prevents a comma-decimal-locale input like '45,5' silently becoming 455. NaN and +/-Infinity are also rejected even if they parse.","triggerScenarios":"Any numeric property routed through SafeParseDouble: rotation (non-PPT), charspacing, crop, width, twips, trendline.forward/backward/intercept, axis min/max/unit, logBase, alpha, etc. Triggered by non-numeric text, a locale-comma decimal ('45,5'), thousands grouping ('1,000'), 'NaN', 'Infinity', or trailing units left on the value.","commonSituations":"Passing '45,5' in a comma-decimal locale (must be '45.5'); passing '100%' with the '%' still attached when the caller did not strip it; empty string for a numeric field; copy-pasting '1.024,5' (EU format) from a spreadsheet.","solutions":["Use a plain invariant-culture number, e.g. '45.5' with a dot decimal and no thousands separators.","Strip any unit suffix ('%', 'pt', 'cm', 'in') only if the specific caller documents it strips them — otherwise pass the bare number.","For locale-comma decimals, convert to a dot decimal before submitting."],"exampleFix":"// before\ncharspacing=\"45,5\"\n// after\ncharspacing=\"45.5\"","handlingStrategy":"validation","validationCode":"// Pre-validate with the SAME NumberStyles.Float rule the parser uses:\nstatic bool IsFiniteNumber(string value)\n    => double.TryParse(value, System.Globalization.NumberStyles.Float,\n           System.Globalization.CultureInfo.InvariantCulture, out var d)\n       && !double.IsNaN(d) && !double.IsInfinity(d);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always use a dot decimal and no thousands separators for numeric properties.","Strip unit suffixes only where the caller documents it strips them.","Convert locale-comma decimals to dot decimals before submission."],"tags":["parsing","input-validation","numeric","locale","officecli"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}