{"record":{"id":"40059a0fe5b6c4a7","repo":"iOfficeAI/OfficeCLI","slug":"invalid-propertyname-value-value-degrees","errorCode":null,"errorMessage":"Invalid '{propertyName}' value '{value}': degrees must be in [-3600, 3600].","messagePattern":"Invalid '(.+?)' value '(.+?)': degrees must be in \\[-3600, 3600\\]\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Core/ParseHelpers.cs","lineNumber":506,"sourceCode":"            || 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;\n    }\n\n    /// <summary>\n    /// Convert a linear-gradient angle in whole degrees to OOXML\n    /// ST_PositiveFixedAngle units (60000ths of a degree). The raw\n    /// `degrees * 60000` multiply overflows Int32 for |degrees| ≳ 35792\n    /// (e.g. 99999° wraps to a garbage 1.7e9 angle that real Excel refuses\n    /// with 0x800A03EC). Reducing modulo 360 first keeps the value in the\n    /// spec range [0, 21600000) — geometrically identical, overflow-proof,\n    /// and always producing a file Excel accepts. Shared by the shape and\n    /// chart gradient builders so their angle handling stays consistent.\n    /// </summary>\n    public static int GradientAngleToOoxmlUnits(int degrees)\n    {\n        var normalized = ((degrees % 360) + 360) % 360;\n        return normalized * 60000;\n    }","sourceCodeStart":488,"sourceCodeEnd":524,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Core/ParseHelpers.cs#L488-L524","documentation":"Thrown by ParseHelpers.SafeParseRotationDegrees when a rotation value (in degrees) falls outside [-3600, 3600]. The clamp exists because OOXML stores angles as ST_Angle (60000ths of a degree); the deg*60000 multiply risks Int32 overflow near +/-35792°, and anything beyond ~ten revolutions is geometrically identical to its mod-360 reduction. Applied uniformly across PPT shape/group/connector add+set rotation sites.","triggerScenarios":"Calling PPT add shape/group/connector or Set shape/group with rotation outside [-3600, 3600], e.g. rotation=\"9999\", rotation=\"-5000\", or rotation=\"3601\".","commonSituations":"Passing radians by mistake (e.g. '6.28' is fine, but '6280' is not); typing a full-circle value like '7200'; computing rotation from a formula that did not mod-360; confusing this PPT degree input with Excel's separate 0-180 uint rotation.","solutions":["Reduce the angle modulo 360 before submitting, or keep it within [-3600, 3600] degrees.","Confirm the value is in degrees, not radians (radians*180/pi).","Do not confuse with Excel text rotation (SafeParseUint, 0-180) — this is the PPT/shape degree rotation."],"exampleFix":"// before\nrotation=\"9999\"\n// after\nrotation=\"279\"   // 9999 % 360","handlingStrategy":"validation","validationCode":"static bool IsValidRotationDegrees(string value)\n{\n    return double.TryParse(value, System.Globalization.NumberStyles.Float,\n               System.Globalization.CultureInfo.InvariantCulture, out var d)\n           && !double.IsNaN(d) && !double.IsInfinity(d)\n           && d >= -3600 && d <= 3600;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Reduce angles modulo 360 before submission.","Confirm degrees vs radians (radians*180/pi).","Do not confuse PPT degree rotation with Excel's 0-180 uint rotation."],"tags":["parsing","input-validation","rotation","pptx","ooxml","officecli"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}