iOfficeAI/OfficeCLI · error · ArgumentException

Invalid range '{spec}': offsets must be non-negative.

Error message

Invalid range '{spec}': offsets must be non-negative.

What it means

Thrown by ParseCharRange when the spec parses as two integers but either offset is negative. Character offsets are 0-based, so negative values are invalid. This guard runs after the format check and before the end>=start check.

Source

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

    }

    /// <summary>
    /// Parse a "start:end" character-range spec into 0-based, half-open offsets.
    /// Colon separator mirrors the officecli range convention (Excel A1:B2).
    /// Shared by the pptx and docx run-range formatting paths so the two never
    /// diverge (CONSISTENCY(char-range)).
    /// </summary>
    public static (int Start, int End) ParseCharRange(string spec)
    {
        var parts = spec.Split(':');
        if (parts.Length != 2
            || !int.TryParse(parts[0].Trim(), CultureInfo.InvariantCulture, out var start)
            || !int.TryParse(parts[1].Trim(), CultureInfo.InvariantCulture, out var end))
            throw new ArgumentException(
                $"Invalid range '{spec}'. Expected 'start:end' with 0-based integer " +
                "character offsets (e.g. '6:11').");
        if (start < 0 || end < 0)
            throw new ArgumentException($"Invalid range '{spec}': offsets must be non-negative.");
        if (end < start)
            throw new ArgumentException($"Invalid range '{spec}': end ({end}) must be >= start ({start}).");
        return (start, end);
    }

    /// <summary>
    /// 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(','))

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Ensure both offsets are >= 0.
  2. Guard computed offsets: if (start < 0 || end < 0) skip/report.
  3. Treat a no-selection case (start==end) explicitly instead of using negatives as a sentinel.

Example fix

// before
var start = matchIndex - 1; // matchIndex 0 -> -1
var spec = $"{start}:{end}";
ParseCharRange(spec); // throws 299

// after
var start = Math.Max(0, matchIndex);
var spec = $"{start}:{end}";
ParseCharRange(spec);
Defensive patterns

Strategy: validation

Validate before calling

if (start < 0 || end < 0)
{ start = Math.Max(0, start); end = Math.Max(0, end); }

Type guard

static bool AreNonNegativeOffsets(string spec)
{ var p = spec.Split(':');
  return int.TryParse(p[0].Trim(), CultureInfo.InvariantCulture, out var s)
      && int.TryParse(p[1].Trim(), CultureInfo.InvariantCulture, out var e)
      && s >= 0 && e >= 0; }

Try / catch

try { range = ParseCharRange(spec); }
catch (ArgumentException ex) when (ex.Message.Contains("non-negative"))
{ /* clamp offsets to 0 and retry */ }

Prevention

When it happens

Trigger: Passing "-1:5", "0:-3", or an offset computed from (match - 1) when match was 0. A find-result offset that underflowed because the match was at the start of the string.

Common situations: Off-by-one math that yields -1 at the document start; converting 1-based offsets to 0-based by subtracting too much; an empty selection expressed as -1:-1.

Related errors


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