iOfficeAI/OfficeCLI · error · ArgumentException

Invalid srcRect '{compound}'. Expected 'l=10,r=10,t=5,b=5' (

Error message

Invalid srcRect '{compound}'. Expected 'l=10,r=10,t=5,b=5' (any subset; values are percent 0-100). For raw l/t/r/b numbers use cropLeft/cropTop/cropRight/cropBottom keys.

What it means

ParseSrcRect parses the 'srcRect' property as comma-separated key=value pairs where keys are exactly l/r/t/b and values are percentages 0-100. If NONE of the pieces parse to a recognized key with a valid value, it throws rather than silently returning null (which would wipe an existing srcRect because the caller replaces on null). For raw ordered numbers use the 'crop=l,t,r,b' composite or the cropLeft/cropTop/cropRight/cropBottom keys instead.

Source

Thrown at src/officecli/Handlers/Excel/ExcelHandler.Helpers.Drawing.cs:113

        int? l = null, r = null, t = null, b = null;
        if (properties.TryGetValue("srcRect", out var compound) && !string.IsNullOrWhiteSpace(compound))
        {
            // Track whether any piece parsed so we can throw a clear error
            // instead of silently no-oping (which would also wipe existing
            // srcRect because the caller replaces with ParseSrcRect's null).
            bool anyParsed = false;
            foreach (var piece in compound.Split(',', StringSplitOptions.RemoveEmptyEntries))
            {
                var kv = piece.Split('=', 2);
                if (kv.Length != 2) continue;
                var key = kv[0].Trim().ToLowerInvariant();
                var val = ParseCropPercent(kv[1]);
                if (!val.HasValue) continue;
                switch (key) { case "l": l = val; break; case "r": r = val; break; case "t": t = val; break; case "b": b = val; break; }
                anyParsed = true;
            }
            if (!anyParsed)
                throw new ArgumentException(
                    $"Invalid srcRect '{compound}'. Expected 'l=10,r=10,t=5,b=5' (any subset; values are percent 0-100). "
                    + "For raw l/t/r/b numbers use cropLeft/cropTop/cropRight/cropBottom keys.");
        }
        // CONSISTENCY(picture-crop): bare composite `crop=l,t,r,b` — the exact
        // form Get emits (and pptx Add already accepts). Without it, dump→batch
        // replay warned UNSUPPORTED and silently dropped the srcRect.
        if (properties.TryGetValue("crop", out var cropAll) && !string.IsNullOrWhiteSpace(cropAll)
            && !cropAll.Contains('='))
        {
            var cropParts = cropAll.Split(',');
            var cropVals = cropParts.Length == 4
                ? cropParts.Select(ParseCropPercent).ToArray()
                : null;
            if (cropVals == null || !cropVals.All(v => v.HasValue))
                throw new ArgumentException(
                    $"Invalid crop '{cropAll}'. Expected four comma-separated percentages in l,t,r,b order (e.g. '10,15,5,20').");
            l = cropVals[0]; t = cropVals[1]; r = cropVals[2]; b = cropVals[3];
        }

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Use srcRect=l=10,r=10,t=5,b=5 (any subset of l/r/t/b is fine).
  2. For ordered numbers, use crop=10,15,5,20 instead.
  3. For per-side control use crop.l/crop.t/crop.r/crop.b keys.
  4. Validate that at least one l/r/t/b key parses before calling.

Example fix

// before
props["srcRect"] = "10,15,5,20";     // numbers, no keys -> throw
props["srcRect"] = "left=10,right=10"; // wrong keys -> throw

// after
props["srcRect"] = "l=10,r=10,t=5,b=5"; // key form
// or, for the same ordered numbers:
props["crop"] = "10,15,5,20";
Defensive patterns

Strategy: validation

Validate before calling

static bool IsValidSrcRect(string s)
{
    bool any = false;
    foreach (var piece in s.Split(',', StringSplitOptions.RemoveEmptyEntries))
    {
        var kv = piece.Split('=', 2);
        if (kv.Length != 2) continue;
        var key = kv[0].Trim().ToLowerInvariant();
        if (key is not ("l" or "r" or "t" or "b")) continue;
        if (!int.TryParse(kv[1].Trim(), out var v) || v < 0 || v > 100) continue;
        any = true;
    }
    return any;
}

if (!string.IsNullOrWhiteSpace(srcRect) && !IsValidSrcRect(srcRect))
    throw new ArgumentException($"Bad srcRect '{srcRect}'; use l/r/t/b=<0-100> pairs");

Type guard

static bool IsValidSrcRect(string s) =>
    s.Split(',', StringSplitOptions.RemoveEmptyEntries)
     .Select(p => p.Split('=', 2))
     .Where(kv => kv.Length == 2)
     .Any(kv => (kv[0].Trim().ToLowerInvariant() is "l" or "r" or "t" or "b")
                && int.TryParse(kv[1].Trim(), out var v) && v is >= 0 and <= 100);

Prevention

When it happens

Trigger: srcRect=left=10,right=10 (wrong keys -- must be l/r/t/b); srcRect=10,15,5,20 (numbers without keys -- that form belongs to 'crop'); srcRect=abc; srcRect=l=10;right=5 (mixed valid/invalid where none parse).

Common situations: Confusing the srcRect key form with the crop ordered form; using full-word keys 'left/top/right/bottom'; pasting a raw numeric crop into srcRect.

Related errors


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