{"record":{"id":"b1b9447cd187b1bd","repo":"iOfficeAI/OfficeCLI","slug":"plugin-contract-violation-b1b944","errorCode":"plugin_contract_violation","errorMessage":"Exporter plugin '{plugin.Manifest.Name}' reported success but no output file was written at {outPath}.","messagePattern":"Exporter plugin '(.+?)' reported success but no output file was written at (.+?)\\.","errorType":"exception","errorClass":"CliException","httpStatus":null,"severity":"error","filePath":"src/officecli/Core/Plugins/ExporterInvoker.cs","lineNumber":80,"sourceCode":"            };\n\n        if (result.ExitCode != 0)\n            throw new CliException(\n                $\"Exporter plugin '{plugin.Manifest.Name}' failed (exit {result.ExitCode}): {Truncate(result.Stderr, 500)}\")\n            {\n                Code = result.ExitCode switch\n                {\n                    2 => \"corrupt_input\",\n                    3 => \"unsupported_feature\",\n                    4 => \"license_expired\",\n                    5 => \"protocol_mismatch\",\n                    6 => \"plugin_idle_timeout\",\n                    _ => \"plugin_failed\",\n                },\n            };\n\n        if (!File.Exists(outPath))\n            throw new CliException(\n                $\"Exporter plugin '{plugin.Manifest.Name}' reported success but no output file was written at {outPath}.\")\n            { Code = \"plugin_contract_violation\" };\n\n        return new ExportResult(outPath, plugin, residentClosed);\n    }\n\n    /// <summary>\n    /// Find an exporter for (source, target). Indexed by target extension (the\n    /// plugin's declared extensions field); filtered by source via the manifest's\n    /// supports list. A plugin missing supports is assumed to accept all native\n    /// sources — conservative default for older manifests.\n    /// </summary>\n    public static ResolvedPlugin? Resolve(string sourceExt, string targetExt)\n    {\n        var p = PluginRegistry.FindFor(PluginKind.Exporter, targetExt);\n        if (p is null) return null;\n\n        if (p.Manifest.Supports is null || p.Manifest.Supports.Count == 0)","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Core/Plugins/ExporterInvoker.cs#L62-L98","documentation":"CliException (code 'plugin_contract_violation') thrown when the exporter exited 0 but File.Exists(outPath) is false — the plugin reported success yet wrote nothing to the declared output path.","triggerScenarios":"Exporter returns exit 0 without creating/writing the file at outPath; wrote to a different path; output path points at an unwritable location and the plugin swallowed the error.","commonSituations":"Plugin bug (success path on empty conversion); outPath directory missing or read-only; plugin writes to a temp path and forgets to move; encoding/locale altering the path.","solutions":["Confirm the outPath directory exists and is writable.","Reproduce and capture the exporter's actual output location via process/file tracing.","Treat exit-0-with-no-file as a plugin bug and report upstream with the source file."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"var dir = Path.GetDirectoryName(outPath);\nif (!Directory.Exists(dir)) Directory.CreateDirectory(dir!);\nif (!HasWriteAccess(dir!)) throw new InvalidOperationException(\"outPath dir not writable.\");","typeGuard":null,"tryCatchPattern":"try { ExporterInvoker.Run(source, targetExt, outPath); }\ncatch (CliException ex) when (ex.Code == \"plugin_contract_violation\" && ex.Message.Contains(\"no output file was written\"))\n{ /* verify outPath dir; treat persistent case as plugin bug */ }","preventionTips":["Pre-create and permission-check the output directory.","Treat exit-0-with-no-file as a plugin defect; capture actual output path via tracing.","Validate outPath is absolute and writable before invoking."],"tags":["plugins","exporter","filesystem","contract","cli-exception"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}