iOfficeAI/OfficeCLI · error · CliException
plugin_contract_violation
plugin_contract_violation
Error message
Dump-reader plugin '{plugin.Manifest.Name}' emitted invalid JSON at item #{itemIndex}: {ex.Message} What it means
CliException (code 'plugin_contract_violation') thrown when JsonSerializer.Deserialize<BatchItem> throws a JsonException on a buffered line, surfaced with the offending item index (0-based). Parse is deferred from the line callback to this main-thread replay loop for consistent item-index semantics.
Source
Thrown at src/officecli/Core/Plugins/DumpReaderInvoker.cs:156
};
// v6.4: now that the plugin has exited and all JSONL is buffered,
// open the handler on this thread and replay synchronously. See
// the rationale comment at the bufferedLines declaration above
// (OpenXml SDK package state not thread-safe under heavy
// multi-part Update-mode mutation).
using (var handler = DocumentHandlerFactory.Open(tmpOut, editable: true))
{
foreach (var line in bufferedLines)
{
BatchItem? item;
try
{
item = JsonSerializer.Deserialize(line, BatchJsonContext.Default.BatchItem);
}
catch (JsonException ex)
{
throw new CliException(
$"Dump-reader plugin '{plugin.Manifest.Name}' emitted invalid JSON at item #{itemIndex}: {ex.Message}")
{ Code = "plugin_contract_violation" };
}
if (item is null)
throw new CliException(
$"Dump-reader plugin '{plugin.Manifest.Name}' emitted null at item #{itemIndex}.")
{ Code = "plugin_contract_violation" };
try
{
CommandBuilder.ExecuteBatchItem(handler, item, json: false);
}
catch (Exception ex)
{
throw new CliException(
$"Dump-reader plugin '{plugin.Manifest.Name}' command #{itemIndex} ({item.Command}) failed while replaying: {ex.Message}", ex)
{ Code = "plugin_command_failed" };
}View on GitHub (pinned to 1ced45e900)
Solutions
- Capture the plugin's raw stdout and inspect the line at the reported item index.
- Validate each emitted line parses as a BatchItem against BatchJsonContext before shipping the plugin.
- Ensure the plugin flushes complete lines and never writes partial JSON on crash.
Defensive patterns
Strategy: try-catch
Validate before calling
// Plugin-side: validate each line before printing.
var parsed = JsonSerializer.Deserialize<BatchItem>(line, BatchJsonContext.Default.BatchItem);
if (parsed is null) throw new InvalidOperationException("Bad line"); Try / catch
try { DumpReaderInvoker.Run(source, ext); }
catch (CliException ex) when (ex.Code == "plugin_contract_violation" && ex.Message.Contains("invalid JSON"))
{ /* capture plugin output, report item index from message */ } Prevention
- Plugin CI should round-trip every emitted line through BatchJsonContext.
- Never write partial JSON; flush only complete lines.
- Log the offending line index when surfacing to users.
When it happens
Trigger: A JSONL line that is not valid JSON, or valid JSON that does not match the BatchItem schema (wrong types, missing required members). Trailing partial line from a crashed plugin is a common cause.
Common situations: Plugin truncated mid-line due to a crash; plugin emits a BatchItem with an unexpected property type; encoding mismatch producing stray bytes after BOM trim.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13).
Data as JSON: /api/errors/6a354f2597155518.
Report an issue: GitHub.