iOfficeAI/OfficeCLI · error · ArgumentException
Invalid sheet name 'History': reserved by Excel for the chan
Error message
Invalid sheet name 'History': reserved by Excel for the change-history sheet.
What it means
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.
Source
Thrown at src/officecli/Handlers/Excel/ExcelHandler.Helpers.Validation.cs:335
}
internal static void ValidateSheetName(string name)
{
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentException("Invalid sheet name: name cannot be empty or whitespace.");
if (name.Length > 31)
throw new ArgumentException(
$"Invalid sheet name '{name}': length {name.Length} exceeds Excel's 31-char limit.");
var forbidden = new[] { '\\', '/', '?', '*', ':', '[', ']' };
var hit = name.IndexOfAny(forbidden);
if (hit >= 0)
throw new ArgumentException(
$"Invalid sheet name '{name}': contains forbidden character '{name[hit]}'. Excel rejects any of: \\ / ? * : [ ]");
if (name.StartsWith('\'') || name.EndsWith('\''))
throw new ArgumentException(
$"Invalid sheet name '{name}': cannot start or end with an apostrophe (').");
if (name.Equals("History", StringComparison.OrdinalIgnoreCase))
throw new ArgumentException(
"Invalid sheet name 'History': reserved by Excel for the change-history sheet.");
}
/// <summary>
/// R35-3: cross-workbook cell formulas like "=[Other.xlsx]Sheet1!A1" or
/// "=[1]Sheet1!A1" need an externalLinks part to resolve. Without one,
/// Excel opens the file but the formula shows #REF!. Reject up-front
/// rather than silently persist a broken formula.
/// CONSISTENCY(cross-workbook-ref): mirrors the namedrange refersTo
/// guard in ExcelHandler.Add.Tables.cs (R27-1).
/// </summary>
internal static void RejectCrossWorkbookFormula(string formula)
{
if (string.IsNullOrEmpty(formula)) return;
var trimmed = formula.TrimStart('=', ' ', '\t');
// CONSISTENCY(cross-workbook-vs-structured-ref): the older `^\[` guard
// also matched OOXML structured table references like `[@Price]` and
// `[Price]*[Qty]`, falsely rejecting valid Excel-365 formulas. RealView on GitHub (pinned to 1ced45e900)
Solutions
- Rename to a non-reserved alternative: 'ChangeLog', 'AuditTrail', 'EditHistory'.
- Maintain a reserved-names list and disambiguate at the input boundary.
Example fix
// before
wb.AddSheet("History");
// after
wb.AddSheet("ChangeLog"); Defensive patterns
Strategy: validation
Validate before calling
static string AvoidReservedSheetName(string n) =>
n.Equals("History", StringComparison.OrdinalIgnoreCase) ? n + "_" : n; Try / catch
try { wb.AddSheet(name); }
catch (ArgumentException ex) when (ex.Message.Contains("reserved")) {
wb.AddSheet(name + "_");
} Prevention
- Keep a reserved-names set ('History' today; check Excel docs for version additions).
- For audit/changelog tabs, prefer explicit non-reserved labels like 'ChangeLog'.
When it happens
Trigger: AddSheet or rename to any casing of 'History' — HISTORY, history, HiStOrY all trip the OrdinalIgnoreCase equality check.
Common situations: Generic 'History' label for an audit log or changelog tab; localized or styled variants; auto-generated names that happen to collide.
Related errors
- Property 'sqref' (or 'range'/'ref') is required for validati
- Invalid sheet name: name cannot be empty or whitespace.
- Invalid sheet name '{name}': length {name.Length} exceeds Ex
- Invalid sheet name '{name}': contains forbidden character '{
- Invalid sheet name '{name}': cannot start or end with an apo
AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13).
Data as JSON: /api/errors/9550444216b9707a.
Report an issue: GitHub.