router-for-me/CLIProxyAPI · error

target executor plugin id is required

Error message

target executor plugin id is required

What it means

executorAdapterForPlugin trims the plugin ID and requires it to be non-empty. An empty or whitespace-only pluginID (for example a model name like "::model" or "/some-model" that yields an empty plugin segment) produces this error before any plugin lookup happens.

Source

Thrown at internal/pluginhost/executor_route.go:118

	return adapter.ExecuteStream(ctx, (*coreauth.Auth)(nil), req, opts)
}

// CountPluginExecutor executes a count-tokens request with the named plugin executor without changing the requested model.
func (h *Host) CountPluginExecutor(ctx context.Context, pluginID string, req coreexecutor.Request, opts coreexecutor.Options) (coreexecutor.Response, error) {
	adapter, errAdapter := h.executorAdapterForPlugin(pluginID)
	if errAdapter != nil {
		return coreexecutor.Response{}, errAdapter
	}
	return adapter.CountTokens(ctx, (*coreauth.Auth)(nil), req, opts)
}

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

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Check the request's model/plugin routing configuration: the target plugin id must be a non-empty, trimmed identifier.
  2. Validate the pluginID at the point where it is extracted (model name parsing) and reject malformed model strings early.
  3. Confirm the plugin's registered id in its manifest matches what the router passes.

Example fix

# before (config.yaml)
models:
  - name: "my-model"
    plugin: ""   # empty -> error

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

Strategy: validation

Validate before calling

pluginID = strings.TrimSpace(pluginID)
if pluginID == "" {
    return fmt.Errorf("model %q has no plugin prefix", modelName)
}

Type guard

func validPluginID(id string) bool {
    id = strings.TrimSpace(id)
    return id != "" && !strings.ContainsAny(id, " \t/")
}

Try / catch

adapter, err := host.ExecutorAdapterForPlugin(pluginID)
if err != nil && strings.Contains(err.Error(), "plugin id is required") {
    return fmt.Errorf("routing bug: empty plugin id extracted from model %q", rawModel)
}

Prevention

When it happens

Trigger: Routing a request with a model identifier whose plugin prefix is empty after trimming: misconfigured model-to-plugin mapping, model string starting with the separator, or caller passing an unset pluginID variable.

Common situations: Config maps a model to a plugin executor but the plugin id field is left blank; dynamic code builds the pluginID from user input that is empty; a model alias regex produces an empty capture.

Related errors


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