iOfficeAI/OfficeCLI · error · CliException
corrupt_batch
corrupt_batch
Error message
Plugin '{resolved.Manifest.Name}' emitted a JSON array; protocol v1 requires JSONL (one BatchItem per line). What it means
The plugin protocol v1 requires JSONL on stdout — exactly one BatchItem JSON object per line. This fires when the first non-whitespace character of a stdout line is '[', meaning the plugin emitted a whole JSON array. A JSON array cannot be streamed line-by-line, so it is treated as a corrupt batch.
Source
Thrown at src/officecli/CommandBuilder.Plugins.cs:284
};
// The plugin's declared target format determines which schema
// tree to validate emitted props against (default: docx).
var schemaFormat = resolved.Manifest.ResolveTargetFormat();
// Run the plugin and stream JSONL.
var items = new List<BatchItem>();
var findings = new List<LintFinding>();
void OnLine(string raw)
{
// Mirrors DumpReaderInvoker: strip per-line UTF-8 BOM so a
// plugin that BOMs every JSONL line passes lint as well as
// it passes invocation.
var line = raw.TrimStart('').Trim();
if (line.Length == 0) return;
if (line[0] == '[')
throw new CliException(
$"Plugin '{resolved.Manifest.Name}' emitted a JSON array; protocol v1 requires JSONL (one BatchItem per line).")
{ Code = "corrupt_batch" };
BatchItem? item;
try { item = JsonSerializer.Deserialize(line, BatchJsonContext.Default.BatchItem); }
catch (JsonException ex)
{
throw new CliException(
$"Plugin '{resolved.Manifest.Name}' emitted invalid JSON at line #{items.Count}: {ex.Message}")
{ Code = "plugin_contract_violation" };
}
if (item is null) return;
items.Add(item);
}
var idle = resolved.Manifest.ResolveIdleTimeout("dump");
var runResult = PluginProcess.Run(new PluginProcess.RunOptions
{View on GitHub (pinned to 1ced45e900)
Solutions
- Emit one JSON object per line (JSONL), not a wrapping array.
- In the plugin, serialize each BatchItem and WriteLine it immediately (streaming).
- Remove any leading '[' debug output.
Example fix
// before (plugin stdout): [{"type":"add",...},{"type":"add",...}]
// after (plugin stdout): {"type":"add",...}
{"type":"add",...} Defensive patterns
Strategy: validation
Validate before calling
// Plugin author: assert stdout is JSONL before publishing.
foreach (var item in items)
Console.WriteLine(JsonSerializer.Serialize(item)); // object per line, no array wrapper Type guard
static bool IsJsonLNotArray(string firstLine) =>
firstLine.TrimStart().Length > 0 && firstLine.TrimStart()[0] != '['; Try / catch
// Lint runner: catch corrupt_batch and report as a plugin fix.
try { LintPlugin(plugin, fixture); }
catch (CliException e) when (e.Code == "corrupt_batch") {
ReportPluginDefect($"{plugin} must emit JSONL, not a JSON array.");
} Prevention
- Protocol v1 = JSONL (one object/line), never a top-level array.
- Stream items with WriteLine as they are produced.
- Unit-test plugin stdout: every non-empty line must parse as a standalone object.
When it happens
Trigger: A dump-reader plugin, when invoked with 'dump <fixture>', prints '[{...},{...}]' (a JSON array) instead of '{...}\n{...}\n' (JSONL).
Common situations: Plugin author used a JSON serializer's array mode; ported a library that emits arrays; the plugin prints a debug header array before items.
Related errors
- plugin_contract_violation
- unsupported_plugin_kind
- lint_fixture_missing
- plugin_idle_timeout
- plugin_failed
AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13).
Data as JSON: /api/errors/7d05a3d093f2d25e.
Report an issue: GitHub.