iOfficeAI/OfficeCLI · error · ArgumentException
Defined name '{nrName}' collides with the table name '{exist
Error message
Defined name '{nrName}' collides with the table name '{existingTable.Name?.Value ?? existingTable.DisplayName?.Value}'. Excel requires table and defined names to be unique in one namespace; pick a different name. What it means
Thrown by AddNamedRange after the new defined name is built but before it is appended. It scans every TableDefinitionPart across all worksheet parts and compares the candidate name against each table's Name and DisplayName (OrdinalIgnoreCase). In OOXML, defined names and ListObject table names share one namespace; a clash passes schema validation but real Excel refuses the file with 0x800A03EC, so the handler rejects it up front instead of writing a corrupt workbook.
Source
Thrown at src/officecli/Handlers/Excel/ExcelHandler.Add.Tables.cs:207
if (!string.Equals(existingName, nrName, StringComparison.OrdinalIgnoreCase)) continue;
if (existingDn.LocalSheetId?.Value == dnLocalId)
throw new ArgumentException(
$"Defined name '{nrName}' already exists" +
(dnLocalId.HasValue ? $" in sheet scope (localSheetId={dnLocalId})" : " in workbook scope") +
"; remove it before adding a new one or pick a different name.");
}
// Mirror of the table-side check: Excel's name namespace spans
// defined names AND ListObject table names; a collision passes
// schema validation but real Excel refuses the file (0x800A03EC).
foreach (var existingTable in _doc.WorkbookPart!.WorksheetParts
.SelectMany(wp => wp.TableDefinitionParts)
.Select(tdp => tdp.Table)
.Where(t => t != null)!)
{
if (string.Equals(existingTable!.Name?.Value, nrName, StringComparison.OrdinalIgnoreCase)
|| string.Equals(existingTable.DisplayName?.Value, nrName, StringComparison.OrdinalIgnoreCase))
throw new ArgumentException(
$"Defined name '{nrName}' collides with the table name '{existingTable.Name?.Value ?? existingTable.DisplayName?.Value}'. Excel requires table and defined names to be unique in one namespace; pick a different name.");
}
definedNames.AppendChild(dn);
// R7-3: if the defined-name body is a formula (not just a pure
// range reference), set fullCalcOnLoad so Excel recomputes on
// first open — otherwise the name evaluates to 0 until the
// user triggers a recalc.
if (LooksLikeFormulaBody(refVal))
{
var calcPr = workbook.GetFirstChild<CalculationProperties>();
if (calcPr == null)
{
calcPr = new CalculationProperties();
var insertBefore = (DocumentFormat.OpenXml.OpenXmlElement?)workbook.GetFirstChild<DocumentFormat.OpenXml.Spreadsheet.OleSize>()
?? (DocumentFormat.OpenXml.OpenXmlElement?)workbook.GetFirstChild<DocumentFormat.OpenXml.Spreadsheet.CustomWorkbookViews>()
?? (DocumentFormat.OpenXml.OpenXmlElement?)workbook.GetFirstChild<DocumentFormat.OpenXml.Spreadsheet.PivotCaches>();View on GitHub (pinned to 1ced45e900)
Solutions
- Pick a distinct name= value for the named range (e.g. prefix it with rng_).
- Rename or remove the colliding table first via Set on its displayName or Remove of the table path.
- Keep a single source of truth for names so tables and defined ranges never share an identifier.
Example fix
// before
handler.Add("/namedrange", "namedrange", null,
new() { ["name"] = "Sales", ["ref"] = "Sheet1!$A$1:$D$10" });
// table 'Sales' already exists -> collision
// after
handler.Add("/namedrange", "namedrange", null,
new() { ["name"] = "rng_Sales", ["ref"] = "Sheet1!$A$1:$D$10" }); Defensive patterns
Strategy: try-catch
Validate before calling
string nrName = properties.GetValueOrDefault("name", "");
var taken = _doc.WorkbookPart!.WorksheetParts
.SelectMany(wp => wp.TableDefinitionParts)
.Select(tdp => tdp.Table)
.Where(t => t != null)
.SelectMany(t => new[] { t!.Name?.Value, t.DisplayName?.Value });
if (taken.Any(n => n != null && n.Equals(nrName, StringComparison.OrdinalIgnoreCase)))
throw new InvalidOperationException($"name '{nrName}' is already a table name"; Try / catch
try { handler.Add("/namedrange", "namedrange", null, props); }
catch (ArgumentException ex) when (ex.Message.Contains("collides with the table name"))
{
// prompt for a new name or rename/remove the table, then retry once
} Prevention
- Maintain one name registry covering both tables and defined ranges.
- Prefix generated defined-range names (e.g. rng_) to keep namespaces disjoint.
- Before bulk adds, list existing table names and diff against your candidate names.
When it happens
Trigger: Call handler.Add(parentPath, type:"namedrange" (or "definedname"/"name"), ..., properties with name=X) when any table whose Name or DisplayName equals X already exists anywhere in the workbook.
Common situations: Auto-generated range names that reuse a table name; a pipeline that adds a table and then a same-named defined range in the same run; importing a dataset whose header string becomes both a table name and a named range.
Related errors
- Unknown totals-row function '{tok}'. Valid: sum, average, co
- Merge range '{refUpper}' overlaps ListObject table '{tblName
- Invalid defined-name '{nrName}': must start with a letter/un
- Property 'sqref' (or 'range'/'ref') is required for validati
- Sheet not found: {tblSheetName}
AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13).
Data as JSON: /api/errors/cd879ba897f14d95.
Report an issue: GitHub.