iOfficeAI/OfficeCLI · error · ArgumentException

Invalid range '{spec}'. Expected one or more 'start:end' ran

Error message

Invalid range '{spec}'. Expected one or more 'start:end' ranges (e.g. '6:11' or '6:11,20:25').

What it means

Thrown by ParseHelpers.ParseCharRanges when the comma-separated range spec yields zero valid ranges. The function splits on ',', trims, skips empty segments, and collects each via ParseCharRange; if nothing remains it rejects the spec. This guards against silently treating a malformed/empty range= as 'no ranges'.

Source

Thrown at src/officecli/Core/ParseHelpers.cs:466

    /// Parse a comma-separated list of "start:end" character ranges into 0-based,
    /// half-open offset pairs (e.g. "6:11,20:25" → [(6,11),(20,25)]). A single
    /// range needs no comma. This lets one range= command target several disjoint
    /// spans — the same shape find's format path produces from multiple matches —
    /// so range is a complete addressing alternative wherever the caller already
    /// knows the offsets. Order is preserved; the caller applies them (format-only
    /// run splitting does not shift character offsets, so any order is safe).
    /// </summary>
    public static List<(int Start, int End)> ParseCharRanges(string spec)
    {
        var result = new List<(int Start, int End)>();
        foreach (var seg in spec.Split(','))
        {
            var trimmed = seg.Trim();
            if (trimmed.Length == 0) continue;
            result.Add(ParseCharRange(trimmed));
        }
        if (result.Count == 0)
            throw new ArgumentException(
                $"Invalid range '{spec}'. Expected one or more 'start:end' ranges " +
                "(e.g. '6:11' or '6:11,20:25').");
        // Normalize to ascending position order (by Start, then End) regardless of
        // the order the caller listed them. This matches find, whose matches are
        // inherently position-ordered, and lets a future text-mutating path process
        // ranges back-to-front (descending) so earlier offsets stay valid — the same
        // reason ProcessFindInParagraph iterates its matches in reverse.
        result.Sort((a, b) => a.Start != b.Start ? a.Start.CompareTo(b.Start) : a.End.CompareTo(b.End));
        return result;
    }

    /// <summary>
    /// Safely parse a string as double, throwing ArgumentException with a clear message on failure.
    /// </summary>
    public static double SafeParseDouble(string value, string propertyName)
    {
        // NumberStyles.Float (NOT the default Float|AllowThousands) — matches every
        // other numeric parser in this file. AllowThousands would silently strip a

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Provide at least one valid 'start:end' pair, e.g. range="6:11" or range="6:11,20:25".
  2. If the caller should treat an absent range as 'no-op', omit the range key entirely rather than passing an empty string.
  3. When building the spec programmatically, filter out empty entries before joining.

Example fix

// before
range=""
// after
range="6:11"
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the spec is non-empty and contains at least one non-empty segment:
static bool HasAtLeastOneRange(string spec)
    => spec.Split(',').Any(s => !string.IsNullOrWhiteSpace(s));

Prevention

When it happens

Trigger: Passing range="" , range="," , range=" , , " (only empty segments), or range=" : " (a segment that is empty after trimming). Any of these leaves the result list empty.

Common situations: Passing an empty string when 'range' was unset but the key still present in a JSON/properties dict; trailing commas from programmatic list joining (e.g. string.Join(",", offsets) over an empty collection); whitespace-only values from copy-paste.

Related errors


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