iOfficeAI/OfficeCLI · error · ArgumentException
Batch input must be a JSON array. Got: {rootKind.ToString().
Error message
Batch input must be a JSON array. Got: {rootKind.ToString().ToLowerInvariant()}. Wrap a single item like [{"command":"get","path":"/"}]. What it means
Thrown when the batch JSON root (after any envelope auto-unwrap) is neither an array nor null. The pre-validation at line 282-294 converts what used to be a generic JsonException exposing the C# type name into a stable, model-agnostic ArgumentException naming the actual root kind and how to fix it (wrap a single item in an array).
Source
Thrown at src/officecli/CommandBuilder.Batch.cs:291
&& jsonDoc.RootElement.TryGetProperty("data", out var envData)
&& envData.ValueKind == System.Text.Json.JsonValueKind.Array)
{
jsonText = envData.GetRawText();
jsonDoc.Dispose();
jsonDoc = System.Text.Json.JsonDocument.Parse(jsonText);
}
using var _jsonDocOwner = jsonDoc;
var rootKind = jsonDoc.RootElement.ValueKind;
if (rootKind != System.Text.Json.JsonValueKind.Array
&& rootKind != System.Text.Json.JsonValueKind.Null)
{
// BUG-R7-10: when the batch input is a JSON object/string/etc.
// (not an array), Deserialize<List<BatchItem>> threw a generic
// JsonException whose message exposed the C# generic type name
// (`System.Collections.Generic.List`1[OfficeCli.BatchItem]`).
// Convert it to a human-friendly error first so AI agents and
// humans see a stable, model-agnostic diagnostic.
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)}");View on GitHub (pinned to 1ced45e900)
Solutions
- Wrap the item(s) in a JSON array: `[{"command":"get","path":"/"}]`.
- If piping from `dump --json`, the envelope auto-unwrap handles `{"data":[...]}`; ensure data is an array.
- Validate the root kind before sending: `jq type ops.json` should report `array`.
Example fix
// before
{"command":"get","path":"/"}
// after
[{"command":"get","path":"/"}] Defensive patterns
Strategy: validation
Validate before calling
// Pre-check the batch root kind.
using var d = System.Text.Json.JsonDocument.Parse(jsonText);
if (d.RootElement.ValueKind != System.Text.Json.JsonValueKind.Array
&& d.RootElement.ValueKind != System.Text.Json.JsonValueKind.Null)
throw new ArgumentException("batch input must be a JSON array; wrap single items in []"); Type guard
// Guard: root is array (after optional envelope unwrap).
static bool IsBatchArrayRoot(string json)
{
try
{
using var d = System.Text.Json.JsonDocument.Parse(json);
var k = d.RootElement.ValueKind;
if (k == System.Text.Json.JsonValueKind.Object
&& d.RootElement.TryGetProperty("data", out var data)
&& data.ValueKind == System.Text.Json.JsonValueKind.Array) return true;
return k == System.Text.Json.JsonValueKind.Array || k == System.Text.Json.JsonValueKind.Null;
}
catch { return false; }
} Prevention
- Always emit batch ops as an array, even for a single command.
- Validate with `jq type` (expect `array`) in shell pipelines before batch.
When it happens
Trigger: `officecli batch file.docx --commands '{"command":"get"}'` (bare object), or `--commands '"hello"'` (string), or `--commands '42'` (number). After envelope unwrap the root kind is object/string/number, not array/null.
Common situations: An agent emits a single command as an object instead of a one-element array; a hand-written JSON uses an object root; the input was a dump envelope whose `data` was not an array; copy-paste dropped the enclosing `[ ]`.
Related errors
- batch item[{ri}]: unknown field(s) {string.Join(", ", unknow
- batch item[{ni}] is null. Each entry must be a JSON object (
- Expected "key=value" string in props array
- Unexpected end of JSON
- Expected object or ["key=value"] array for props
AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13).
Data as JSON: /api/errors/f4a7393d1fa6f108.
Report an issue: GitHub.