iOfficeAI/OfficeCLI · error · ArgumentException

Invalid 'lineSpacing' value '{value}'. Line spacing must not

Error message

Invalid 'lineSpacing' value '{value}'. Line spacing must not be negative.

What it means

Thrown by the pt branch of ParseWordLineSpacing when a fixed (Exact) line-spacing value in points is negative. Note '0pt' is deliberately allowed because paired with lineRule=atLeast it round-trips Word's 'no minimum line height'; only negatives are rejected. The cm/in branches reject zero too via RequirePositive (see error 417). ArgumentException.

Source

Thrown at src/officecli/Core/SpacingConverter.cs:187

        }

        // "150%" → multiplier (negative permitted under the Auto rule)
        if (trimmed.EndsWith("%", StringComparison.Ordinal))
        {
            var num = RequireNonZero(ParseNumberAllowNegative(trimmed[..^1], "lineSpacing"), value);
            return ((int)Math.Round(num / 100.0 * WordAutoLineSpacingUnit), true);
        }

        // "18pt" → fixed (Exact). "0pt" is allowed: paired with
        // lineRule=atLeast it round-trips Word's <w:spacing w:line="0"
        // w:lineRule="atLeast"/> ("no minimum line height") — dropping it
        // re-rendered those paragraphs at the style's default line height
        // and reflowed the page. Negative still rejected.
        if (trimmed.EndsWith("pt", StringComparison.OrdinalIgnoreCase))
        {
            var num = ParseNumber(trimmed[..^2], "lineSpacing");
            if (num < 0)
                throw new ArgumentException($"Invalid 'lineSpacing' value '{value}'. Line spacing must not be negative.");
            return ((int)Math.Round(num * TwipsPerPoint), false);
        }

        // "0.5cm" → fixed (Exact), convert to points first
        if (trimmed.EndsWith("cm", StringComparison.OrdinalIgnoreCase))
        {
            var num = RequirePositive(ParseNumber(trimmed[..^2], "lineSpacing"), value);
            return ((int)Math.Round(num * PointsPerCm * TwipsPerPoint), false);
        }

        // "0.5in" → fixed (Exact)
        if (trimmed.EndsWith("in", StringComparison.OrdinalIgnoreCase))
        {
            var num = RequirePositive(ParseNumber(trimmed[..^2], "lineSpacing"), value);
            return ((int)Math.Round(num * PointsPerInch * TwipsPerPoint), false);
        }

        // Bare number → multiplier under Auto rule, mirrors the "1.5x" path.

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Use a non-negative point value (e.g. '18pt'); '0pt' is acceptable for atLeast round-tripping.
  2. If you need a negative auto line spacing, use the multiplier form ('-1.5x') which permits negatives, not the fixed pt form.
  3. Confirm the intended lineRule before choosing the value form.

Example fix

// before
set paragraph lineSpacing=-18pt
// after
set paragraph lineSpacing=18pt
Defensive patterns

Strategy: validation

Validate before calling

var trimmed = value.Trim();
if (trimmed.EndsWith("pt", StringComparison.OrdinalIgnoreCase))
{
    var n = double.Parse(trimmed[..^2], CultureInfo.InvariantCulture);
    if (n < 0) throw new ArgumentException("lineSpacing pt must not be negative");
}
var r = SpacingConverter.ParseWordLineSpacing(value);

Try / catch

try { var (tw, mult) = SpacingConverter.ParseWordLineSpacing(value); }
catch (ArgumentException ex) when (ex.Message.Contains("must not be negative"))
{ /* use a non-negative pt value; 0pt is allowed for atLeast */ }

Prevention

When it happens

Trigger: Passing a negative point value such as '-18pt' as a fixed Word lineSpacing. The pt branch parses the number and checks num < 0.

Common situations: A negative value copied from an auto/multiplier context (where negatives are legal) into the fixed pt form, or a script bug producing a negative length.

Related errors


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