{"record":{"id":"fdd99140a9b6db1d","repo":"iOfficeAI/OfficeCLI","slug":"invalid-linespacing-value-raw-line-spacing-fdd991","errorCode":null,"errorMessage":"Invalid 'lineSpacing' value '{raw}'. Line spacing must not be zero.","messagePattern":"Invalid 'lineSpacing' value '(.+?)'\\. Line spacing must not be zero\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Core/SpacingConverter.cs","lineNumber":160,"sourceCode":"        // BUG-R7-04: lineSpacing must not be zero. Zero produces degenerate\n        // OOXML (w:spacing/@line=0 is undefined in MS-DOC) and Office silently\n        // collapses to single-spacing — surface the error to the user instead.\n        static double RequirePositive(double n, string raw)\n        {\n            if (n <= 0)\n                throw new ArgumentException($\"Invalid 'lineSpacing' value '{raw}'. Line spacing must be greater than 0.\");\n            return n;\n        }\n\n        // Auto/multiplier line spacing maps to w:line, which is\n        // ST_SignedTwipsMeasure — negatives are schema-legal and real docs\n        // carry them (e.g. <w:spacing w:line=\"-310\" w:lineRule=\"auto\"/> in a\n        // style). Reject only zero (degenerate per BUG-R7-04); allow negative\n        // so such styles round-trip instead of failing the whole add op.\n        static double RequireNonZero(double n, string raw)\n        {\n            if (n == 0)\n                throw new ArgumentException($\"Invalid 'lineSpacing' value '{raw}'. Line spacing must not be zero.\");\n            return n;\n        }\n\n        // \"1.5x\" → multiplier (negative permitted under the Auto rule)\n        if (trimmed.EndsWith(\"x\", StringComparison.OrdinalIgnoreCase))\n        {\n            var num = RequireNonZero(ParseNumberAllowNegative(trimmed[..^1], \"lineSpacing\"), value);\n            return ((int)Math.Round(num * WordAutoLineSpacingUnit), true);\n        }\n\n        // \"150%\" → multiplier (negative permitted under the Auto rule)\n        if (trimmed.EndsWith(\"%\", StringComparison.Ordinal))\n        {\n            var num = RequireNonZero(ParseNumberAllowNegative(trimmed[..^1], \"lineSpacing\"), value);\n            return ((int)Math.Round(num / 100.0 * WordAutoLineSpacingUnit), true);\n        }\n\n        // \"18pt\" → fixed (Exact). \"0pt\" is allowed: paired with","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Core/SpacingConverter.cs#L142-L178","documentation":"Thrown by the RequireNonZero local in ParseWordLineSpacing when a multiplier-form line spacing value ('1.5x', '150%', or a bare number) is exactly zero. Auto/multiplier line spacing maps to w:line (ST_SignedTwipsMeasure); negatives are schema-legal and allowed for round-tripping real styles, but zero is degenerate (BUG-R7-04) and rejected. ArgumentException.","triggerScenarios":"Passing '0x', '0%', or a bare '0' as Word lineSpacing — these enter the multiplier ('x'/'%'/bare) branches which call RequireNonZero. A negative like '-1.5x' is accepted; only zero throws.","commonSituations":"A user passes 0 intending 'no extra spacing' or single-line, or a script defaults an unset field to 0. Real style sheets sometimes carry negative auto line values which are intentionally permitted here.","solutions":["Use '1x' or '100%' for single-line spacing instead of 0.","If a negative multiplier comes from an existing style, it will round-trip fine — no action needed.","Ensure scripts do not default lineSpacing to 0; use a positive multiplier or a fixed pt value."],"exampleFix":"// before\nset paragraph lineSpacing=0x\n// after\nset paragraph lineSpacing=1x","handlingStrategy":"validation","validationCode":"var trimmed = value.Trim();\nif (trimmed.EndsWith(\"x\") || trimmed.EndsWith(\"%\") || (!trimmed.EndsWith(\"pt\") && !trimmed.EndsWith(\"cm\") && !trimmed.EndsWith(\"in\")))\n{\n    var n = double.Parse(trimmed.TrimEnd('%','x'), CultureInfo.InvariantCulture);\n    if (n == 0) throw new ArgumentException(\"lineSpacing multiplier must not be zero\");\n}\nvar r = SpacingConverter.ParseWordLineSpacing(value);","typeGuard":null,"tryCatchPattern":"try { var (tw, mult) = SpacingConverter.ParseWordLineSpacing(value); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"must not be zero\"))\n{ /* use 1x/100% for single spacing; negative multipliers are allowed */ }","preventionTips":["Never default lineSpacing to 0; use '1x' for single-line.","Negative auto/multiplier values from real styles are fine — only zero throws.","Validate multiplier-form inputs are non-zero before applying."],"tags":["spacing","word","line-spacing","argument","validation"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}