router-for-me/CLIProxyAPI · error

plugin %s does not declare an executor

Error message

plugin %s does not declare an executor

What it means

The plugin with the given ID is active but its manifest/capability set has no Executor capability (record.plugin.Capabilities.Executor == nil). The host was asked to build an executor adapter for a plugin that simply does not provide model execution.

Source

Thrown at internal/pluginhost/executor_route.go:129

func (h *Host) executorAdapterForPlugin(pluginID string) (*executorAdapter, error) {
	if h == nil {
		return nil, fmt.Errorf("plugin host is unavailable")
	}
	pluginID = strings.TrimSpace(pluginID)
	if pluginID == "" {
		return nil, fmt.Errorf("target executor plugin id is required")
	}
	for _, record := range h.activeRecords() {
		if record.id != pluginID {
			continue
		}
		if h.isPluginFused(record.id) {
			return nil, fmt.Errorf("plugin executor %s is unavailable", pluginID)
		}
		executor := record.plugin.Capabilities.Executor
		if executor == nil {
			return nil, fmt.Errorf("plugin %s does not declare an executor", pluginID)
		}
		provider, okProvider := h.executorProvider(record, executor)
		if !okProvider {
			return nil, fmt.Errorf("plugin executor %s has no provider identifier", pluginID)
		}
		registration := newExecutorAdapterRegistration(h, record, provider, executor)
		return registration.adapter, nil
	}
	return nil, fmt.Errorf("plugin executor %s not found", pluginID)
}

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Verify the plugin's manifest declares an executor capability and that its id matches the routing config exactly.
  2. Correct the model-to-plugin mapping in config to point at the plugin that actually provides the executor.
  3. Update/reinstall the plugin to a version that declares Executor.

Example fix

# before (config.yaml)
models:
  - name: "my-model"
    plugin: "my-auth-plugin"     # no executor capability

# after
models:
  - name: "my-model"
    plugin: "my-executor-plugin" # declares Executor
Defensive patterns

Strategy: validation

Validate before calling

for _, rec := range host.ActiveRecords() {
    if rec.ID == wantedPluginID && rec.Plugin.Capabilities.Executor != nil {
        return nil // routing target is valid
    }
}
return fmt.Errorf("plugin %s has no executor capability", wantedPluginID)

Type guard

func pluginDeclaresExecutor(rec pluginRecord) bool {
    return rec.Plugin.Capabilities.Executor != nil
}

Try / catch

adapter, err := host.ExecutorAdapterForPlugin(pluginID)
if err != nil && strings.Contains(err.Error(), "does not declare an executor") {
    return configErrorf("model %s routed to non-executor plugin %s; fix models config", model, pluginID)
}

Prevention

When it happens

Trigger: Routing execution to a plugin that only provides auth, command-line, or router capabilities; typo in the plugin id in model routing config that happens to match a non-executor plugin; plugin version that dropped or renamed the executor capability.

Common situations: Config lists the wrong plugin id for a model; plugin downgrade where executor support was removed; a manifest parsing issue silently dropping the Executor capability.

Related errors


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/3e2b689da2c82427. Report an issue: GitHub.