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

  1. Capture the plugin's raw stdout and inspect the line at the reported item index.
  2. Validate each emitted line parses as a BatchItem against BatchJsonContext before shipping the plugin.
  3. 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

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

Related errors


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