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

  1. Pick a distinct name= value for the named range (e.g. prefix it with rng_).
  2. Rename or remove the colliding table first via Set on its displayName or Remove of the table path.
  3. 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

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


AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13). Data as JSON: /api/errors/cd879ba897f14d95. Report an issue: GitHub.