{"record":{"id":"7f4680437be4e510","repo":"iOfficeAI/OfficeCLI","slug":"invalid-paramname-value-raw","errorCode":null,"errorMessage":"Invalid {paramName} value: '{raw}'.","messagePattern":"Invalid (.+?) value: '(.+?)'\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"warning","filePath":"src/officecli/Core/DrawingEffectsHelper.cs","lineNumber":356,"sourceCode":"        // dimension so callers can write \"5pt\", \"45deg\", \"40%\" without\n        // forcing them to know the internal unit. Strip and parse the\n        // numeric prefix; reject unknown trailing letters.\n        var num = raw.Trim();\n        if (num.Length == 0)\n            throw new ArgumentException($\"Invalid {paramName} value: '{raw}' (empty).\");\n        // Strip a trailing alpha unit suffix (pt/deg/%/cm/in/px/emu). The\n        // numeric routes through pt/deg/% as-is — units other than pt for a\n        // pt-dimension still parse the number but the result is not\n        // converted; agents should stick to bare numbers or the native unit\n        // for now. The point of this fix is to stop ParseParam throwing on\n        // a unit-qualified token; a future pass can do real unit conversion.\n        int suffixStart = num.Length;\n        while (suffixStart > 0 && (char.IsLetter(num[suffixStart - 1]) || num[suffixStart - 1] == '%'))\n            suffixStart--;\n        var numPart = num[..suffixStart];\n        if (!double.TryParse(numPart, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out var val)\n            || double.IsNaN(val) || double.IsInfinity(val))\n            throw new ArgumentException($\"Invalid {paramName} value: '{raw}'.\");\n        return val;\n    }\n\n    /// <summary>\n    /// Split an effect value string into [\"color\", \"p1\", \"p2\", …] tokens.\n    /// Historical separator is '-', but '-' collides with negative numbers\n    /// (e.g. \"red;-5\" for a shadow with negative angle). Prefer ';' when\n    /// present; fall back to '-' for the legacy form. Empty tokens are\n    /// rejected up front so opacity/blur don't silently take the default\n    /// for a malformed input like \"red;;5\".\n    /// </summary>\n    private static string[] SplitEffectParts(string value)\n    {\n        if (string.IsNullOrEmpty(value))\n            throw new ArgumentException(\"Effect value cannot be empty.\");\n        // Prefer ';' so negative numeric params (e.g. \"-5\") survive split.\n        // When ';' is present, treat '-' as part of a numeric value, not a\n        // separator. Fall back to '-' for the legacy form. In ';' mode,","sourceCodeStart":338,"sourceCodeEnd":374,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Core/DrawingEffectsHelper.cs#L338-L374","documentation":"ParseParam strips a trailing alpha/% unit suffix (pt/deg/%/cm/in/px/emu) from the token, then requires the remaining numeric part to parse as a finite double under invariant culture. If it doesn't (or is NaN/infinity), it throws with the raw token. The strip lets callers write '5pt'/'45deg'/'40%' for the native dimension, but other units are not converted.","triggerScenarios":"A token whose numeric prefix won't parse: 'abc', '5..5', 'pt' (suffix only, empty number), '5,5' (comma under invariant culture), or a value with an unrecognized leading symbol. numPart after stripping letters/% isn't a finite double.","commonSituations":"Locale decimal separator (comma) on a culture where invariant rejects it; a stray character in the number; only a unit suffix with no digits; double decimal points.","solutions":["Use a '.' decimal separator and a clean numeric prefix.","Ensure the token has digits before the optional unit suffix ('5pt', not 'pt').","Only append a recognized suffix (pt/deg/%/cm/in/px/emu); unrecognized trailing letters become part of the failed parse."],"exampleFix":"// before — comma decimal under invariant culture\neffect=\"shadow:red;5,5;45\"\n\n// after — dot decimal\neffect=\"shadow:red;5.5;45\"","handlingStrategy":"validation","validationCode":"static bool IsValidEffectParam(string token)\n{\n    var num = token.Trim();\n    int s = num.Length;\n    while (s > 0 && (char.IsLetter(num[s - 1]) || num[s - 1] == '%')) s--;\n    var np = num[..s];\n    return np.Length > 0\n        && double.TryParse(np, NumberStyles.Float, CultureInfo.InvariantCulture, out var v)\n        && !double.IsNaN(v) && !double.IsInfinity(v);\n}","typeGuard":null,"tryCatchPattern":"try { effect = DrawingEffectsHelper.Build(value); }\ncatch (ArgumentException ex) when (ex.Message.StartsWith(\"Invalid \", StringComparison.Ordinal) && ex.Message.Contains(\"value:\", StringComparison.Ordinal))\n{ errors.Add(ex.Message); }","preventionTips":["Use a '.' decimal separator and invariant-friendly numerics.","Ensure digits precede any unit suffix.","Only append recognized suffixes (pt/deg/%/cm/in/px/emu)."],"tags":["effect","parsing","validation","units","user-input","drawing"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}