iOfficeAI/OfficeCLI · error · ArgumentException
columns. .dxfId requires a numeric dxf id, got
Error message
columns.{n}.dxfId requires a numeric dxf id, got: '{rawVal}' What it means
Thrown by AddTable at the application stage when a columns.N.dxfId / column.N.dxfId property fails uint.TryParse as the value is written to the TableColumn.DataFormatId. This is a defensive re-check mirroring the pre-validation at line 1304; under normal flow the earlier guard catches bad values first. Reaching this throw implies the property set changed between the two loops or the guard was bypassed.
Solutions
- Treat it identically to error 590: ensure every columns.N.dxfId / column.N.dxfId is a non-negative integer.
- If you see this instead of 590, check whether the properties dictionary was mutated between the pre-check and application (e.g. a rebind).
- Remove the dxfId property when no data formatting is required.
Example fix
// before --prop columns.1.dxfId=abc // after --prop columns.1.dxfId=3
Defensive patterns
Strategy: validation
Validate before calling
// Same guard as 590; run it before Add so the pre-validation (1304) catches bad values,
// not the application-stage throw (1477).
static bool TryValidateDxfIds(Dictionary<string,string> props, out string error)
{
error = null;
foreach (var (k, v) in props)
{
if (!(k.StartsWith("columns.") || k.StartsWith("column.")) || !k.EndsWith(".dxfId")) continue;
if (!uint.TryParse(v, out _)) { error = $"{k} requires a numeric dxf id, got: '{v}'"; return false; }
}
return true;
} Type guard
static bool IsValidDxfId(string v) => uint.TryParse(v, out _);
Try / catch
try { handler.Add(parentPath, "table", null, props); }
catch (ArgumentException ex) when (ex.Message.Contains("requires a numeric dxf id"))
{ /* same remediation as 590: fix/remove the dxfId, then retry */ } Prevention
- Run the same dxfId validation before Add so error 590 is the one you see, not 591.
- Do not mutate the properties dictionary between Add entry and table serialization.
- Treat any 591 hit as a sign the property set changed mid-flow.
When it happens
Trigger: Reaching this point requires a columns.N.dxfId value that is non-numeric yet passed the earlier pre-validation, which should not happen in normal use; effectively a duplicate guard for the same condition.
Common situations: Same as 590: non-integer dxf ids. In practice callers hit 590 first; 591 is a backstop.
Related errors
- columns. .dxfId requires a numeric dxf id, got
- criteria . requires a numeric value, got
- Defined name ' ' collides with the table name ' '. Excel…
- Merge range ' ' overlaps ListObject table ' ' (ref ' ')…
- Property 'ref' or 'range' is required for table
AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13).
Data as JSON: /api/errors/7e2eb704ab2a40e9.
Report an issue: GitHub.
Appendix: source
Thrown at src/officecli/Handlers/Excel/ExcelHandler.Add.Tables.cs:1477
// target tableColumn (N is 1-based). The id must reference
// an existing workbook differentialFormats entry; we do not
// synthesize new dxfs here — users who want inline style
// values should register a dxf first via `add dxf` (or the
// underlying APIs) and then reference it.
// Read each candidate columns.N.dxfId via TryGetValue so the
// TrackingPropertyDictionary marks consumed keys accessed — a plain
// `foreach (var (rawKey, rawVal) in properties)` goes through the
// Dictionary<,> enumerator and bypasses access tracking
// (the project conventions handler-as-truth). N is 1-based; both `column.` and
// `columns.` prefixes are accepted, mirroring the old regex.
var tblColList = tableColumns.Elements<TableColumn>().ToList();
for (int n = 1; n <= tblColList.Count; n++)
{
if (!properties.TryGetValue($"columns.{n}.dxfId", out var rawVal)
&& !properties.TryGetValue($"column.{n}.dxfId", out rawVal))
continue;
if (!uint.TryParse(rawVal, out var dxfId))
throw new ArgumentException(
$"columns.{n}.dxfId requires a numeric dxf id, got: '{rawVal}'");
tblColList[n - 1].DataFormatId = dxfId;
}
// T2 — wire the banded rows/columns + first/last column
// flags onto the TableStyleInfo. Each accepts `showX` or
// its alias; default matches the old hard-coded values so
// omitting them is identical to previous behavior.
table.AppendChild(new TableStyleInfo
{
Name = styleName,
ShowFirstColumn = (properties.TryGetValue("showFirstColumn", out var sfc)
|| properties.TryGetValue("firstColumn", out sfc)
|| properties.TryGetValue("firstCol", out sfc))
? IsTruthy(sfc) : false,
ShowLastColumn = (properties.TryGetValue("showLastColumn", out var slc)
|| properties.TryGetValue("lastColumn", out slc)
|| properties.TryGetValue("lastCol", out slc))View on GitHub (pinned to 1ced45e900)