iOfficeAI/OfficeCLI · error · ArgumentException

batch item[ ]: unknown field(s) . Valid fields

Error message

batch item[{ri}]: unknown field(s) {string.Join(", ", unknown.Select(f => "\"" + f + "\""))}. Valid fields: {string.Join(", ", BatchItem.KnownFields)}

What it means

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.

Solutions

  1. Correct the field name(s) listed in the error to one from the Valid fields list in the message.
  2. Re-run `dump` on a reference document to see the exact field names the current version expects.
  3. Remove genuinely unsupported fields rather than relying on silent skip.

Example fix

// before
[{"comand":"get","path":"/"}]

// after
[{"command":"get","path":"/"}]
Defensive patterns

Strategy: validation

Validate before calling

// Validate each item's keys against the known set.
using var d = System.Text.Json.JsonDocument.Parse(jsonText);
foreach (var elem in d.RootElement.EnumerateArray())
    foreach (var p in elem.EnumerateObject())
        if (!BatchItem.KnownFields.Contains(p.Name))
            throw new ArgumentException($"unknown field {p.Name}");

Type guard

// Guard: all item keys are known.
static bool AllKeysKnown(string json, IReadOnlyCollection<string> known)
{
    try
    {
        using var d = System.Text.Json.JsonDocument.Parse(json);
        foreach (var e in d.RootElement.EnumerateArray())
            foreach (var p in e.EnumerateObject())
                if (!known.Contains(p.Name)) return false;
        return true;
    }
    catch { return false; }
}

Prevention

When it happens

Trigger: `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.

Common situations: 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.

Related errors


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

Appendix: source

Thrown at src/officecli/CommandBuilder.Batch.cs:309

                throw new ArgumentException(
                    $"Batch input must be a JSON array. Got: {rootKind.ToString().ToLowerInvariant()}. "
                    + "Wrap a single item like [{\"command\":\"get\",\"path\":\"/\"}].");
            }
            if (jsonDoc.RootElement.ValueKind == System.Text.Json.JsonValueKind.Array)
            {
                int ri = 0;
                foreach (var elem in jsonDoc.RootElement.EnumerateArray())
                {
                    if (elem.ValueKind == System.Text.Json.JsonValueKind.Object)
                    {
                        var unknown = new List<string>();
                        foreach (var prop in elem.EnumerateObject())
                        {
                            if (!BatchItem.KnownFields.Contains(prop.Name))
                                unknown.Add(prop.Name);
                        }
                        if (unknown.Count > 0)
                            throw new ArgumentException($"batch item[{ri}]: unknown field(s) {string.Join(", ", unknown.Select(f => $"\"{f}\""))}. Valid fields: {string.Join(", ", BatchItem.KnownFields)}");
                    }
                    ri++;
                }
            }

            var items = System.Text.Json.JsonSerializer.Deserialize<List<BatchItem>>(jsonText, BatchJsonContext.Default.ListBatchItem) ?? new();
            // NEWLINE-SEMANTICS-V2: strip meta items; rewrite legacy (\n = soft
            // break) docx dumps to the v2 encoding before execution.
            OfficeCli.Core.BatchCompat.PrepareForReplay(items, file.FullName);
            // BUG-R40-B11: explicit null entries (e.g. `[null]`) deserialize
            // to a List<BatchItem> with a null slot and trip a NRE deeper in
            // ExecuteBatchItem. Reject up-front with a recognizable error
            // pointing at the offending index.
            for (int ni = 0; ni < items.Count; ni++)
            {
                if (items[ni] == null)
                    throw new ArgumentException(
                        $"batch item[{ni}] is null. Each entry must be a JSON object (e.g. {{\"command\":\"get\",\"path\":\"/\"}}).");

View on GitHub (pinned to 1ced45e900)