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, nilView on GitHub (pinned to 78f0c4079e)
Solutions
- Check the request's model/plugin routing configuration: the target plugin id must be a non-empty, trimmed identifier.
- Validate the pluginID at the point where it is extracted (model name parsing) and reject malformed model strings early.
- 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
- Validate model-name-to-plugin parsing with unit tests covering empty segments.
- Reject malformed model identifiers at the API boundary, not in the executor layer.
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
- plugin %s does not declare an executor
- plugin executor %s has no provider identifier
- plugin executor %s not found
- auth provider %s returned auth without provider
- auth provider %s returned invalid auth data
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/3901d8f2d071c4a0.
Report an issue: GitHub.