{"record":{"id":"ee7c8bdb81afd511","repo":"iOfficeAI/OfficeCLI","slug":"invalid-defined-name-nrname-single-letter-r","errorCode":null,"errorMessage":"Invalid defined-name '{nrName}': single letter 'R' / 'C' is reserved by Excel for R1C1 reference notation; choose a different name.","messagePattern":"Invalid defined-name '(.+?)': single letter 'R' / 'C' is reserved by Excel for R1C1 reference notation; choose a different name\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Handlers/Excel/ExcelHandler.Add.Tables.cs","lineNumber":66,"sourceCode":"        // reference. Otherwise Excel rejects the file with 0x800A03EC.\n        // \"Letter\" is any Unicode letter (\\p{L}) — Excel accepts CJK/\n        // Cyrillic/etc. names; the previous ASCII-only class falsely\n        // rejected them. Emoji/symbols stay rejected (not \\p{L}).\n        if (!System.Text.RegularExpressions.Regex.IsMatch(nrName, @\"^[\\p{L}_\\\\][\\p{L}\\p{N}_\\\\.]*$\"))\n            throw new ArgumentException($\"Invalid defined-name '{nrName}': must start with a letter/underscore and contain only letters, digits, underscores, or periods (no spaces).\");\n        // Excel caps defined-name identifier length at 255 characters; longer\n        // names are silently truncated on open (or the file is rejected with\n        // 0x800A03EC depending on host). Refuse up front instead of letting\n        // a 256+ char name land on disk and round-trip-differ on re-open.\n        if (nrName.Length > 255)\n            throw new ArgumentException($\"Invalid defined-name '{nrName}': length {nrName.Length} exceeds the Excel 255-character limit.\");\n        if (LooksLikeCellReference(nrName))\n            throw new ArgumentException($\"Invalid defined-name '{nrName}': name parses as a cell reference; choose a different name.\");\n        // R39-5: Excel reserves the single letters R and C (case-insensitive)\n        // because they collide with R1C1 reference notation. Excel rejects\n        // the file with 0x800A03EC if either is used as a defined name.\n        if (nrName.Length == 1 && (nrName[0] == 'R' || nrName[0] == 'r' || nrName[0] == 'C' || nrName[0] == 'c'))\n            throw new ArgumentException($\"Invalid defined-name '{nrName}': single letter 'R' / 'C' is reserved by Excel for R1C1 reference notation; choose a different name.\");\n        // `refersTo` is the common Excel-documented alias for `ref`;\n        // silently map it so users don't end up with an empty\n        // <x:definedName/> that corrupts the file.\n        var refVal = properties.GetValueOrDefault(\"ref\",\n            properties.GetValueOrDefault(\"refersTo\",\n                properties.GetValueOrDefault(\"formula\", \"\")));\n        // R15/bt-2: reject up-front when the required ref/refersTo/formula\n        // value is missing so an empty <x:definedName/> never gets written\n        // (the resulting zombie polluted the workbook and broke later Set\n        // calls). Unsupported aliases like `range=` previously silently\n        // landed here as empty and produced the zombie.\n        if (string.IsNullOrEmpty(refVal))\n            throw new ArgumentException(\"'ref' (or 'refersTo' / 'formula') property is required for namedrange\");\n        // R7-2: per ECMA-376 §18.2.5, <x:definedName> content must NOT\n        // have a leading '=' (unlike the formula-bar form in Excel UI).\n        // Excel rejects the file with 0x800A03EC if '=' is present.\n        if (refVal.StartsWith('='))\n            refVal = refVal.TrimStart('=');","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Handlers/Excel/ExcelHandler.Add.Tables.cs#L48-L84","documentation":"Thrown when the defined name is the single letter R or C (case-insensitive). Excel reserves these because they collide with R1C1 reference notation; using either as a workbook defined name makes Excel reject the file with 0x800A03EC. This is a targeted check that runs after the cell-reference check (554), so it specifically catches the R/C reservation that LooksLikeCellReference does not.","triggerScenarios":"Passing `name=R`, `name=r`, `name=C`, or `name=c`. These single letters pass the identifier regex and the cell-reference check but are independently reserved.","commonSituations":"Using `R` for a 'Row' range or `C` for a 'Column' range as a mnemonic; auto-generated single-letter names.","solutions":["Use a longer name like `RowRange`, `ColRange`, `R_Range`, or any name with more than one character.","Avoid the single letters R and C entirely for defined names."],"exampleFix":"// before\nadd ./book.xlsx /namedrange --type namedrange --prop name=C --prop ref=Sheet1!C:C\n// after\nadd ./book.xlsx /namedrange --type namedrange --prop name=ColRange --prop ref=Sheet1!C:C","handlingStrategy":"validation","validationCode":"if (name.Length == 1 && (name[0] is 'R' or 'r' or 'C' or 'c'))\n    throw new InvalidOperationException(\"Defined name 'R'/'C' is reserved for R1C1 notation\");","typeGuard":"static bool IsNotReservedRc(string? s)\n    => s is null || s.Length != 1 || (s[0] is not 'R' and not 'r' and not 'C' and not 'c');","tryCatchPattern":"try { handler.AddNamedRange(...); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"reserved by Excel for R1C1\"))\n{ /* rename to something longer */ }","preventionTips":["Never use the single letters R or C as defined names.","Use descriptive multi-character names like RowRange/ColRange."],"tags":["excel","named-range","defined-name","reserved-name","input-validation"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}