iOfficeAI/OfficeCLI · error · CliException

exporter_not_found

exporter_not_found

Error message

No exporter plugin found for {sourceExt} → {targetExt}.

What it means

CliException (code 'exporter_not_found') thrown when ExporterInvoker.Resolve(sourceExt, targetExt) returns null — no exporter plugin declares the requested source→target extension pair. Resolve indexes plugins by target extension and filters by the manifest's supports list (a missing supports is treated as accept-all for native sources).

Source

Thrown at src/officecli/Core/Plugins/ExporterInvoker.cs:34

{
    public sealed record ExportResult(string OutputPath, ResolvedPlugin Plugin, bool ResidentClosed);

    /// <summary>
    /// Resolve an exporter for (sourceExt, targetExt) and run it. On success,
    /// the target file exists at <paramref name="outPath"/> and the result
    /// reports which plugin handled it. On failure, throws CliException with
    /// an appropriate code (exporter_not_found, plugin_failed, ...).
    ///
    /// If a resident is holding the source file, it's closed first to release
    /// the exclusive lock; <see cref="ExportResult.ResidentClosed"/> indicates
    /// this happened so the caller can surface it to the user.
    /// </summary>
    public static ExportResult Run(string sourceFullPath, string targetExt, string outPath)
    {
        var sourceExt = Path.GetExtension(sourceFullPath).ToLowerInvariant();

        var plugin = Resolve(sourceExt, targetExt)
            ?? throw new CliException($"No exporter plugin found for {sourceExt} → {targetExt}.")
            {
                Code = "exporter_not_found",
                Suggestion = "Install an exporter plugin: `officecli plugins list` to see what's available, or see plugins/plugin-protocol.md.",
            };

        bool residentClosed = false;
        if (ResidentClient.TryConnect(sourceFullPath, out _))
        {
            if (ResidentClient.SendCloseWithResponse(sourceFullPath, out _))
                residentClosed = true;
        }

        var idle = plugin.Manifest.ResolveIdleTimeout("export");
        var result = PluginProcess.Run(new PluginProcess.RunOptions
        {
            ExecutablePath = plugin.ExecutablePath,
            Arguments = new[] { "export", sourceFullPath, "--out", outPath },
            IdleTimeoutSeconds = idle,

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Run `officecli plugins list` to see installed exporters and their declared extensions.
  2. Install an exporter plugin covering the source→target pair.
  3. Verify the plugin manifest's extensions array lists the target ext and supports lists the source ext.

Example fix

// before: export to pdf with no pdf exporter
officecli export report.docx --out report.pdf

// after
officecli plugins install pdf-exporter
officecli export report.docx --out report.pdf
Defensive patterns

Strategy: validation

Validate before calling

var src = Path.GetExtension(sourcePath).ToLowerInvariant();
var tgt = targetExt.TrimStart('.').ToLowerInvariant();
if (ExporterInvoker.Resolve(src, tgt) is null)
    throw new InvalidOperationException($"No exporter for {src} → .{tgt}; install one.");

Try / catch

try { ExporterInvoker.Run(source, targetExt, outPath); }
catch (CliException ex) when (ex.Code == "exporter_not_found")
{ /* prompt user to install an exporter for the pair */ }

Prevention

When it happens

Trigger: Export invoked with a (source, target) pair no installed exporter covers, e.g. exporting .docx to .pdf without a pdf exporter plugin installed.

Common situations: Target extension not in any plugin's extensions field; plugin present but its supports list excludes the source; plugin uninstalled or install path broken.

Related errors


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