{"record":{"id":"7e2eb704ab2a40e9","repo":"iOfficeAI/OfficeCLI","slug":"columns-n-dxfid-requires-a-numeric-dxf-id-got-7e2eb7","errorCode":null,"errorMessage":"columns.{n}.dxfId requires a numeric dxf id, got: '{rawVal}'","messagePattern":"columns\\.(.+?)\\.dxfId requires a numeric dxf id, got: '(.+?)'","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Handlers/Excel/ExcelHandler.Add.Tables.cs","lineNumber":1477,"sourceCode":"        // target tableColumn (N is 1-based). The id must reference\n        // an existing workbook differentialFormats entry; we do not\n        // synthesize new dxfs here — users who want inline style\n        // values should register a dxf first via `add dxf` (or the\n        // underlying APIs) and then reference it.\n        // Read each candidate columns.N.dxfId via TryGetValue so the\n        // TrackingPropertyDictionary marks consumed keys accessed — a plain\n        // `foreach (var (rawKey, rawVal) in properties)` goes through the\n        // Dictionary<,> enumerator and bypasses access tracking\n        // (the project conventions handler-as-truth). N is 1-based; both `column.` and\n        // `columns.` prefixes are accepted, mirroring the old regex.\n        var tblColList = tableColumns.Elements<TableColumn>().ToList();\n        for (int n = 1; n <= tblColList.Count; n++)\n        {\n            if (!properties.TryGetValue($\"columns.{n}.dxfId\", out var rawVal)\n                && !properties.TryGetValue($\"column.{n}.dxfId\", out rawVal))\n                continue;\n            if (!uint.TryParse(rawVal, out var dxfId))\n                throw new ArgumentException(\n                    $\"columns.{n}.dxfId requires a numeric dxf id, got: '{rawVal}'\");\n            tblColList[n - 1].DataFormatId = dxfId;\n        }\n\n        // T2 — wire the banded rows/columns + first/last column\n        // flags onto the TableStyleInfo. Each accepts `showX` or\n        // its alias; default matches the old hard-coded values so\n        // omitting them is identical to previous behavior.\n        table.AppendChild(new TableStyleInfo\n        {\n            Name = styleName,\n            ShowFirstColumn = (properties.TryGetValue(\"showFirstColumn\", out var sfc)\n                    || properties.TryGetValue(\"firstColumn\", out sfc)\n                    || properties.TryGetValue(\"firstCol\", out sfc))\n                ? IsTruthy(sfc) : false,\n            ShowLastColumn = (properties.TryGetValue(\"showLastColumn\", out var slc)\n                    || properties.TryGetValue(\"lastColumn\", out slc)\n                    || properties.TryGetValue(\"lastCol\", out slc))","sourceCodeStart":1459,"sourceCodeEnd":1495,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Handlers/Excel/ExcelHandler.Add.Tables.cs#L1459-L1495","documentation":"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.","triggerScenarios":"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.","commonSituations":"Same as 590: non-integer dxf ids. In practice callers hit 590 first; 591 is a backstop.","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."],"exampleFix":"// before\n--prop columns.1.dxfId=abc\n// after\n--prop columns.1.dxfId=3","handlingStrategy":"validation","validationCode":"// Same guard as 590; run it before Add so the pre-validation (1304) catches bad values,\n// not the application-stage throw (1477).\nstatic bool TryValidateDxfIds(Dictionary<string,string> props, out string error)\n{\n    error = null;\n    foreach (var (k, v) in props)\n    {\n        if (!(k.StartsWith(\"columns.\") || k.StartsWith(\"column.\")) || !k.EndsWith(\".dxfId\")) continue;\n        if (!uint.TryParse(v, out _)) { error = $\"{k} requires a numeric dxf id, got: '{v}'\"; return false; }\n    }\n    return true;\n}","typeGuard":"static bool IsValidDxfId(string v) => uint.TryParse(v, out _);","tryCatchPattern":"try { handler.Add(parentPath, \"table\", null, props); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"requires a numeric dxf id\"))\n{ /* same remediation as 590: fix/remove the dxfId, then retry */ }","preventionTips":["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."],"tags":["excel","table","validation","numeric-parsing","dxf","defensive-guard"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}