iOfficeAI/OfficeCLI · warning · ArgumentException

Invalid {paramName} value: '{raw}' (empty).

Error message

Invalid {paramName} value: '{raw}' (empty).

What it means

ParseParam reads a positional token from an effect value split into parts. If the token at the requested index exists but trims to zero length, it throws rather than silently substituting the default — so a malformed input like 'red;;5' (empty middle token) is surfaced instead of opacity/blur quietly taking the default.

Source

Thrown at src/officecli/Core/DrawingEffectsHelper.cs:343

    {
        var existing = colorElement.GetFirstChild<Drawing.Alpha>();
        if (existing != null) existing.Remove();
        if (alphaVal == 100000) return;
        colorElement.AppendChild(new Drawing.Alpha { Val = alphaVal });
    }

    private static double ParseParam(string[] parts, int index, double defaultValue, string paramName)
    {
        if (parts.Length <= index) return defaultValue;
        var raw = parts[index];
        // The historical contract is "bare double" — blur/dist in pt, angle
        // in deg, opacity in %. Accept unit-qualified inputs that match each
        // dimension so callers can write "5pt", "45deg", "40%" without
        // forcing them to know the internal unit. Strip and parse the
        // numeric prefix; reject unknown trailing letters.
        var num = raw.Trim();
        if (num.Length == 0)
            throw new ArgumentException($"Invalid {paramName} value: '{raw}' (empty).");
        // Strip a trailing alpha unit suffix (pt/deg/%/cm/in/px/emu). The
        // numeric routes through pt/deg/% as-is — units other than pt for a
        // pt-dimension still parse the number but the result is not
        // converted; agents should stick to bare numbers or the native unit
        // for now. The point of this fix is to stop ParseParam throwing on
        // a unit-qualified token; a future pass can do real unit conversion.
        int suffixStart = num.Length;
        while (suffixStart > 0 && (char.IsLetter(num[suffixStart - 1]) || num[suffixStart - 1] == '%'))
            suffixStart--;
        var numPart = num[..suffixStart];
        if (!double.TryParse(numPart, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out var val)
            || double.IsNaN(val) || double.IsInfinity(val))
            throw new ArgumentException($"Invalid {paramName} value: '{raw}'.");
        return val;
    }

    /// <summary>
    /// Split an effect value string into ["color", "p1", "p2", …] tokens.

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Remove empty tokens — every positional parameter must have a value or be omitted by ending the string.
  2. Use the preferred ';' separator consistently and avoid double delimiters.
  3. If you want the default for a parameter, omit that and all following tokens rather than leaving a blank.

Example fix

// before — empty middle token
effect="shadow:red;;5"

// after — explicit value, or omit to take the default
effect="shadow:red;4;5"
Defensive patterns

Strategy: validation

Validate before calling

static bool HasNoEmptyTokens(string value)
{
    var sep = value.Contains(';') ? ';' : '-';
    foreach (var part in value.Split(sep))
        if (string.IsNullOrWhiteSpace(part)) return false;
    return true;
}

Try / catch

try { effect = DrawingEffectsHelper.Build(value); }
catch (ArgumentException ex) when (ex.Message.Contains("(empty)", StringComparison.Ordinal))
{ errors.Add(ex.Message); }

Prevention

When it happens

Trigger: An effect string with an empty token where a parameter is expected: 'red;;5' (empty blur), 'red;5;' (empty trailing), or a whitespace-only token. parts[index] is present but num.Length == 0 after Trim.

Common situations: User used the wrong separator producing empty fields; trailing delimiter; copy-paste left a blank; mixing ';' and '-' separators produced an empty slot.

Related errors


AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13). Data as JSON: /api/errors/70c6b41be36647dd. Report an issue: GitHub.