{"record":{"id":"2e12fb62a7578460","repo":"iOfficeAI/OfficeCLI","slug":"number-format-has-unbalanced-square-brackets-fo","errorCode":null,"errorMessage":"number format has unbalanced square brackets: '{formatCode}'. Bracket codes ([Red], [>=100], [h]) must be closed; writing an unbalanced bracket makes Excel refuse to open the file.","messagePattern":"number format has unbalanced square brackets: '(.+?)'\\. Bracket codes \\(\\[Red\\], \\[>=100\\], \\[h\\]\\) must be closed; writing an unbalanced bracket makes Excel refuse to open the file\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Core/ExcelStyleManager.cs","lineNumber":742,"sourceCode":"        // Unbalanced [brackets] (e.g. formatCode=\"[\") pass schema validation\n        // but real Excel refuses the whole file (0x800A03EC). Count outside\n        // quoted literals; escaped \\[ is a literal char.\n        int nfBracketDepth = 0;\n        bool nfBrQuote = false;\n        for (int i = 0; i < formatCode.Length; i++)\n        {\n            var c = formatCode[i];\n            if (c == '\"') nfBrQuote = !nfBrQuote;\n            else if (!nfBrQuote && c == '\\\\') i++;\n            else if (!nfBrQuote && c == '[') nfBracketDepth++;\n            else if (!nfBrQuote && c == ']')\n            {\n                nfBracketDepth--;\n                if (nfBracketDepth < 0) break;\n            }\n        }\n        if (nfBracketDepth != 0)\n            throw new ArgumentException(\n                $\"number format has unbalanced square brackets: '{formatCode}'. Bracket codes ([Red], [>=100], [h]) must be closed; writing an unbalanced bracket makes Excel refuse to open the file.\");\n\n        // Unquoted letters outside Excel's token alphabet (date/time/era/\n        // General letters) make real Excel refuse the whole file\n        // (0x800A03EC) while schema validation stays green — e.g. a typoed\n        // numfmt=invalid_fmt instead of \"invalid_fmt\"0. Excel's grammar is\n        // quirky enough (abc opens, xyz does not) that a hard reject risks\n        // false positives on locale codes, so warn instead of block.\n        {\n            const string TokenLetters = \"abcdeghlmnprsty\";\n            bool warnQuote = false;\n            int warnBracket = 0;\n            char? suspect = null;\n            for (int i = 0; i < formatCode.Length && suspect == null; i++)\n            {\n                var c = formatCode[i];\n                if (c == '\"') { warnQuote = !warnQuote; continue; }\n                if (warnQuote) continue;","sourceCodeStart":724,"sourceCodeEnd":760,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Core/ExcelStyleManager.cs#L724-L760","documentation":"Thrown when a custom Excel number format has unbalanced square brackets. Bracket codes ([Red], [>=100], [h]) must be closed; the writer counts brackets outside quoted literals (and treats escaped \\[ as a literal), then rejects the format if the depth is non-zero. Real Excel refuses the whole file (0x800A03EC) on an unbalanced bracket, so this guard blocks it at write time.","triggerScenarios":"Setting numberFormat to a string with an unclosed bracket such as \"[Red\" or \"[>=100\" or a stray \"[\"; the validator counts '[' and ']' ignoring those inside double quotes or after a backslash and throws when depth != 0.","commonSituations":"Hand-building a format string with string interpolation that drops the closing ']'; a typoed predicate like [>100 instead of [>100]; copy-paste truncating the format.","solutions":["Balance the brackets: ensure every '[' has a matching ']' in the format code.","If you need a literal bracket in output, escape it as \\[ or \\] or put it inside a quoted literal \"[\".","Validate the format with the project's number-format checker before writing."],"exampleFix":"// before\nstyle.NumberFormat = \"[Red0.00\"; // missing ]\n// after\nstyle.NumberFormat = \"[Red]0.00\";","handlingStrategy":"validation","validationCode":"static bool BracketsBalanced(string fmt)\n{\n    int depth = 0; bool inQuote = false;\n    for (int i = 0; i < fmt.Length; i++)\n    {\n        var c = fmt[i];\n        if (c == '\"') inQuote = !inQuote;\n        else if (!inQuote && c == '\\\\') i++;\n        else if (!inQuote && c == '[') depth++;\n        else if (!inQuote && c == ']') { depth--; if (depth < 0) return false; }\n    }\n    return depth == 0;\n}","typeGuard":null,"tryCatchPattern":"try { ApplyNumberFormat(fmt); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"unbalanced square brackets\"))\n{ /* fix or escape brackets */ }","preventionTips":["Escape literal brackets as \\[ / \\] or quote them.","Pre-validate bracket balance before writing the format."],"tags":["excel","number-format","validation","brackets"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}