iOfficeAI/OfficeCLI · warning · ArgumentException

Invalid color transform '{token}': value must be an integer.

Error message

Invalid color transform '{token}': value must be an integer.

What it means

The transform name was recognized, but the value portion (after the optional '=') failed int.TryParse. The parser expects a signed integer — either an OOXML raw value (eqForm, 'lumMod=75000') or a percentage ('lumMod75'). A non-integer like 'lumMod=7.5' or 'shadeabc' is rejected.

Source

Thrown at src/officecli/Core/DrawingColorBuilder.cs:119

            //   "lumMod75"        — Get's canonical round-trip form, percent 0..100
            //   "lumMod=75000"    — raw OOXML percentage 0..100000
            //                       (matches the literal a:lumMod@val attribute,
            //                        what users see in PowerPoint XML / docs)
            // Both end up encoded as @val="75000" on the OOXML child. The name is
            // a leading run of letters; the remainder is '='?<signed-int>. Scan the
            // name by letters (not "first digit") so a leading '-' on the value
            // stays with the value instead of being folded into the name.
            int i = 0;
            while (i < token.Length && char.IsLetter(token[i])) i++;
            if (i == 0 || i == token.Length) continue;
            var name = token.Substring(0, i);
            if (!KnownTransforms.Contains(name))
                throw new ArgumentException(
                    $"Unknown color transform '{name}'. Valid: lumMod, lumOff, shade, tint, satMod, satOff, hueMod, hueOff, alpha.");
            bool eqForm = token[i] == '=';
            string numText = eqForm ? token.Substring(i + 1) : token.Substring(i);
            if (!int.TryParse(numText, out var raw))
                throw new ArgumentException(
                    $"Invalid color transform '{token}': value must be an integer.");
            // OOXML splits the transforms into two schema types:
            //   shade / tint / alpha  → ST_PositiveFixedPercentage (0..100%),
            //                           negatives forbidden.
            //   lumMod / lumOff / satMod / satOff / hueMod / hueOff
            //                         → ST_Percentage: SIGNED and may exceed 100%
            //                           (e.g. satMod200% to over-saturate, or
            //                           satOff-10% to desaturate). Rejecting
            //                           negatives wrongly aborted replay of the
            //                           round-trip form Get emits for these
            //                           (satOff val="-10000" → "satOff-10").
            // Only the fixed-percentage family stays clamped 0..100.
            bool fixedPct = name.ToLowerInvariant() is "shade" or "tint" or "alpha";
            int maxPct = fixedPct ? 100 : 1000;       // 1000% headroom for ST_Percentage
            int minPct = fixedPct ? 0 : -1000;        // signed for the Mod/Off family
            int maxRaw = fixedPct ? 100000 : 1000000;
            int minRaw = fixedPct ? 0 : -1000000;
            int pct;

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Provide an integer: raw OOXML form 'lumMod=75000' or percentage form 'lumMod75'.
  2. For fractional percentages, round to the nearest integer percentage.
  3. Drop any stray unit suffix from the value (the parser takes a bare int).

Example fix

// before — decimal value fails int parse
fill="red shade=33.3"

// after — integer percentage
fill="red shade33"
Defensive patterns

Strategy: validation

Validate before calling

static bool IsValidTransformValue(string token)
{
    int i = 0; while (i < token.Length && char.IsLetter(token[i])) i++;
    if (i == 0 || i == token.Length) return false;
    var rest = token[i] == '=' ? token.Substring(i + 1) : token.Substring(i);
    return rest.Length > 0 && int.TryParse(rest, out _);
}

Try / catch

try { DrawingColorBuilder.Build(color); }
catch (ArgumentException ex) when (ex.Message.Contains("value must be an integer", StringComparison.Ordinal))
{ errors.Add(ex.Message); }

Prevention

When it happens

Trigger: A token like 'shade=50.5' (decimal), 'tint=abc', 'lumMod=' (empty value), or 'alpha1.5%' where the numeric part isn't a clean integer. numText is token.Substring after the letter name.

Common situations: User supplies a fractional percentage as a decimal ('shade=33.3') instead of an integer; pastes a value with a stray unit ('lumMod=50%'); leaves the value empty after '='.

Related errors


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