{"record":{"id":"fff5db028cec6049","repo":"iOfficeAI/OfficeCLI","slug":"invalid-spacing-value-value-spacing-must-be-n","errorCode":null,"errorMessage":"Invalid spacing value '{value}'. Spacing must be non-negative.","messagePattern":"Invalid spacing value '(.+?)'\\. Spacing must be non-negative\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Core/SpacingConverter.cs","lineNumber":49,"sourceCode":"{\n    private const double PointsPerCm = 72.0 / 2.54; // ~28.3465\n    private const double PointsPerInch = 72.0;\n    private const int TwipsPerPoint = 20; // 1 pt = 20 twips\n    private const int WordAutoLineSpacingUnit = 240; // 240 twips = single line in Auto mode\n\n    // ────────────────────────────────────────────────────────────────\n    //  spaceBefore / spaceAfter  →  Word twips\n    // ────────────────────────────────────────────────────────────────\n\n    /// <summary>\n    /// Parse a spacing value (spaceBefore/spaceAfter) to Word twips (uint).\n    /// Accepts: \"12pt\", \"0.5cm\", \"0.5in\", or bare number (treated as twips for backward compat).\n    /// </summary>\n    public static uint ParseWordSpacing(string value)\n    {\n        var points = ParseSpacingToPoints(value, bareIsPoints: false);\n        if (points < 0)\n            throw new ArgumentException($\"Invalid spacing value '{value}'. Spacing must be non-negative.\");\n        return (uint)Math.Round(points * TwipsPerPoint);\n    }\n\n    /// <summary>\n    /// Signed twips variant for OOXML attributes typed `ST_SignedTwipsMeasure`:\n    /// w:ind/@w:left, @w:right, @w:start, @w:end, @w:firstLine. Word documents\n    /// commonly carry negative indents — e.g. `<w:ind w:right=\"-46\">` so a\n    /// table-of-contents page-number column overhangs the right margin. Real\n    /// docs (gov.cn corpus) trip ParseWordSpacing's non-negative gate even\n    /// though the OOXML schema explicitly allows negatives for these slots.\n    /// Use this for indent slots only; spaceBefore/spaceAfter remain on the\n    /// strict `ST_TwipsMeasure` path (the non-negative gate there catches\n    /// the silent line-collapse failure mode that motivated it).\n    /// </summary>\n    public static int ParseWordSpacingSigned(string value)\n    {\n        var points = ParseSpacingToPointsSigned(value, bareIsPoints: false);\n        return (int)Math.Round(points * TwipsPerPoint);","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Core/SpacingConverter.cs#L31-L67","documentation":"Thrown by ParseWordSpacing when the parsed point value is negative. ParseWordSpacing converts spaceBefore/spaceAfter to unsigned Word twips (ST_TwipsMeasure, which is non-negative), so negatives are invalid for those slots. Note indent slots (left/right/firstLine) use ParseWordSpacingSigned instead, which allows negatives. ArgumentException.","triggerScenarios":"Passing a negative spaceBefore/spaceAfter value such as '-12pt', '-0.5cm', or '-240' (bare twips) to a Word handler that routes through ParseWordSpacing (e.g. set spacing.spaceBefore).","commonSituations":"A user copies a negative value intended for an indent into a spacing field, or a script feeds a signed measurement into the non-negative spacing slot. Real docs carry negative indents but never negative spaceBefore/spaceAfter.","solutions":["Use a non-negative value for spaceBefore/spaceAfter (e.g. '12pt', '0').","For indent slots that legitimately allow negatives (left/right/start/end/firstLine), use the signed path — the handlers already route those to ParseWordSpacingSigned.","Verify you are setting the correct property: spacing vs indent."],"exampleFix":"// before\nset spacing spaceBefore=-12pt\n// after\nset spacing spaceBefore=12pt","handlingStrategy":"validation","validationCode":"var pts = SpacingConverter.ParsePoints(value); // throws on negative\nif (pts < 0) throw new ArgumentException($\"Non-negative spacing required: {value}\");\n// For indent slots that allow negatives, use ParseWordSpacingSigned instead.","typeGuard":null,"tryCatchPattern":"try { var twips = SpacingConverter.ParseWordSpacing(value); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"Spacing must be non-negative\"))\n{ /* use a non-negative value; switch to ParseWordSpacingSigned only for indent slots */ }","preventionTips":["Use non-negative values for spaceBefore/spaceAfter.","Route indent slots (left/right/firstLine) through ParseWordSpacingSigned.","Do not paste an indent value into a spacing field."],"tags":["spacing","word","argument","validation"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}