{"record":{"id":"9550444216b9707a","repo":"iOfficeAI/OfficeCLI","slug":"invalid-sheet-name-history-reserved-by-excel-fo","errorCode":null,"errorMessage":"Invalid sheet name 'History': reserved by Excel for the change-history sheet.","messagePattern":"Invalid sheet name 'History': reserved by Excel for the change-history sheet\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Handlers/Excel/ExcelHandler.Helpers.Validation.cs","lineNumber":335,"sourceCode":"    }\n\n    internal static void ValidateSheetName(string name)\n    {\n        if (string.IsNullOrWhiteSpace(name))\n            throw new ArgumentException(\"Invalid sheet name: name cannot be empty or whitespace.\");\n        if (name.Length > 31)\n            throw new ArgumentException(\n                $\"Invalid sheet name '{name}': length {name.Length} exceeds Excel's 31-char limit.\");\n        var forbidden = new[] { '\\\\', '/', '?', '*', ':', '[', ']' };\n        var hit = name.IndexOfAny(forbidden);\n        if (hit >= 0)\n            throw new ArgumentException(\n                $\"Invalid sheet name '{name}': contains forbidden character '{name[hit]}'. Excel rejects any of: \\\\ / ? * : [ ]\");\n        if (name.StartsWith('\\'') || name.EndsWith('\\''))\n            throw new ArgumentException(\n                $\"Invalid sheet name '{name}': cannot start or end with an apostrophe (').\");\n        if (name.Equals(\"History\", StringComparison.OrdinalIgnoreCase))\n            throw new ArgumentException(\n                \"Invalid sheet name 'History': reserved by Excel for the change-history sheet.\");\n    }\n\n    /// <summary>\n    /// R35-3: cross-workbook cell formulas like \"=[Other.xlsx]Sheet1!A1\" or\n    /// \"=[1]Sheet1!A1\" need an externalLinks part to resolve. Without one,\n    /// Excel opens the file but the formula shows #REF!. Reject up-front\n    /// rather than silently persist a broken formula.\n    /// CONSISTENCY(cross-workbook-ref): mirrors the namedrange refersTo\n    /// guard in ExcelHandler.Add.Tables.cs (R27-1).\n    /// </summary>\n    internal static void RejectCrossWorkbookFormula(string formula)\n    {\n        if (string.IsNullOrEmpty(formula)) return;\n        var trimmed = formula.TrimStart('=', ' ', '\\t');\n        // CONSISTENCY(cross-workbook-vs-structured-ref): the older `^\\[` guard\n        // also matched OOXML structured table references like `[@Price]` and\n        // `[Price]*[Qty]`, falsely rejecting valid Excel-365 formulas. Real","sourceCodeStart":317,"sourceCodeEnd":353,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Handlers/Excel/ExcelHandler.Helpers.Validation.cs#L317-L353","documentation":"The name 'History' (case-insensitive) is reserved by Excel for the workbook's built-in change-history (Track Changes) sheet. Creating a user sheet with that name corrupts the change-tracking feature, so the library rejects it as the final guard in ValidateSheetName.","triggerScenarios":"AddSheet or rename to any casing of 'History' — HISTORY, history, HiStOrY all trip the OrdinalIgnoreCase equality check.","commonSituations":"Generic 'History' label for an audit log or changelog tab; localized or styled variants; auto-generated names that happen to collide.","solutions":["Rename to a non-reserved alternative: 'ChangeLog', 'AuditTrail', 'EditHistory'.","Maintain a reserved-names list and disambiguate at the input boundary."],"exampleFix":"// before\nwb.AddSheet(\"History\");\n\n// after\nwb.AddSheet(\"ChangeLog\");","handlingStrategy":"validation","validationCode":"static string AvoidReservedSheetName(string n) =>\n    n.Equals(\"History\", StringComparison.OrdinalIgnoreCase) ? n + \"_\" : n;","typeGuard":null,"tryCatchPattern":"try { wb.AddSheet(name); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"reserved\")) {\n    wb.AddSheet(name + \"_\");\n}","preventionTips":["Keep a reserved-names set ('History' today; check Excel docs for version additions).","For audit/changelog tabs, prefer explicit non-reserved labels like 'ChangeLog'."],"tags":["excel","sheet-name","validation","reserved"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}