{"record":{"id":"a9e5f5711d7cc5d6","repo":"iOfficeAI/OfficeCLI","slug":"batch-item-ri-unknown-field-s-string-join","errorCode":null,"errorMessage":"batch item[{ri}]: unknown field(s) {string.Join(\", \", unknown.Select(f => \"\\\"\" + f + \"\\\"\"))}. Valid fields: {string.Join(\", \", BatchItem.KnownFields)}","messagePattern":"batch item\\[(.+?)\\]: unknown field\\(s\\) (.+?)\\. Valid fields: (.+?)","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/CommandBuilder.Batch.cs","lineNumber":309,"sourceCode":"                throw new ArgumentException(\n                    $\"Batch input must be a JSON array. Got: {rootKind.ToString().ToLowerInvariant()}. \"\n                    + \"Wrap a single item like [{\\\"command\\\":\\\"get\\\",\\\"path\\\":\\\"/\\\"}].\");\n            }\n            if (jsonDoc.RootElement.ValueKind == System.Text.Json.JsonValueKind.Array)\n            {\n                int ri = 0;\n                foreach (var elem in jsonDoc.RootElement.EnumerateArray())\n                {\n                    if (elem.ValueKind == System.Text.Json.JsonValueKind.Object)\n                    {\n                        var unknown = new List<string>();\n                        foreach (var prop in elem.EnumerateObject())\n                        {\n                            if (!BatchItem.KnownFields.Contains(prop.Name))\n                                unknown.Add(prop.Name);\n                        }\n                        if (unknown.Count > 0)\n                            throw new ArgumentException($\"batch item[{ri}]: unknown field(s) {string.Join(\", \", unknown.Select(f => $\"\\\"{f}\\\"\"))}. Valid fields: {string.Join(\", \", BatchItem.KnownFields)}\");\n                    }\n                    ri++;\n                }\n            }\n\n            var items = System.Text.Json.JsonSerializer.Deserialize<List<BatchItem>>(jsonText, BatchJsonContext.Default.ListBatchItem) ?? new();\n            // NEWLINE-SEMANTICS-V2: strip meta items; rewrite legacy (\\n = soft\n            // break) docx dumps to the v2 encoding before execution.\n            OfficeCli.Core.BatchCompat.PrepareForReplay(items, file.FullName);\n            // BUG-R40-B11: explicit null entries (e.g. `[null]`) deserialize\n            // to a List<BatchItem> with a null slot and trip a NRE deeper in\n            // ExecuteBatchItem. Reject up-front with a recognizable error\n            // pointing at the offending index.\n            for (int ni = 0; ni < items.Count; ni++)\n            {\n                if (items[ni] == null)\n                    throw new ArgumentException(\n                        $\"batch item[{ni}] is null. Each entry must be a JSON object (e.g. {{\\\"command\\\":\\\"get\\\",\\\"path\\\":\\\"/\\\"}}).\");","sourceCodeStart":291,"sourceCodeEnd":327,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/CommandBuilder.Batch.cs#L291-L327","documentation":"Thrown during pre-deserialization field validation when a batch array element is an object containing one or more keys not in BatchItem.KnownFields. The loop at line 297-312 enumerates each item's properties, collects unknown names, and reports them with the valid field list — catching typos before the lenient deserializer would silently drop them.","triggerScenarios":"`officecli batch file.docx --commands '[{\"comand\":\"get\"}]'` (typo: comand vs command), or an item with `{\"path\":\"/\",\"color\":\"red\"}` where color is not a known field.","commonSituations":"Typo in a field name; an agent invents a field not in the schema; a field renamed across versions is still being sent; copy-paste from a different tool's JSON shape.","solutions":["Correct the field name(s) listed in the error to one from the Valid fields list in the message.","Re-run `dump` on a reference document to see the exact field names the current version expects.","Remove genuinely unsupported fields rather than relying on silent skip."],"exampleFix":"// before\n[{\"comand\":\"get\",\"path\":\"/\"}]\n\n// after\n[{\"command\":\"get\",\"path\":\"/\"}]","handlingStrategy":"validation","validationCode":"// Validate each item's keys against the known set.\nusing var d = System.Text.Json.JsonDocument.Parse(jsonText);\nforeach (var elem in d.RootElement.EnumerateArray())\n    foreach (var p in elem.EnumerateObject())\n        if (!BatchItem.KnownFields.Contains(p.Name))\n            throw new ArgumentException($\"unknown field {p.Name}\");","typeGuard":"// Guard: all item keys are known.\nstatic bool AllKeysKnown(string json, IReadOnlyCollection<string> known)\n{\n    try\n    {\n        using var d = System.Text.Json.JsonDocument.Parse(json);\n        foreach (var e in d.RootElement.EnumerateArray())\n            foreach (var p in e.EnumerateObject())\n                if (!known.Contains(p.Name)) return false;\n        return true;\n    }\n    catch { return false; }\n}","tryCatchPattern":null,"preventionTips":["Generate batch JSON from `dump` or a typed serializer so field names stay in sync with the schema.","Keep BatchItem.KnownFields exported for agent/tooling validation."],"tags":["json","batch","validation","schema","typo"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}