{"record":{"id":"3372674acdae1f96","repo":"router-for-me/CLIProxyAPI","slug":"plugin-host-is-unavailable","errorCode":null,"errorMessage":"plugin host is unavailable","messagePattern":"plugin host is unavailable","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/pluginhost/executor_route.go","lineNumber":114,"sourceCode":"\tadapter, errAdapter := h.executorAdapterForPlugin(pluginID)\n\tif errAdapter != nil {\n\t\treturn nil, errAdapter\n\t}\n\treturn adapter.ExecuteStream(ctx, (*coreauth.Auth)(nil), req, opts)\n}\n\n// CountPluginExecutor executes a count-tokens request with the named plugin executor without changing the requested model.\nfunc (h *Host) CountPluginExecutor(ctx context.Context, pluginID string, req coreexecutor.Request, opts coreexecutor.Options) (coreexecutor.Response, error) {\n\tadapter, errAdapter := h.executorAdapterForPlugin(pluginID)\n\tif errAdapter != nil {\n\t\treturn coreexecutor.Response{}, errAdapter\n\t}\n\treturn adapter.CountTokens(ctx, (*coreauth.Auth)(nil), req, opts)\n}\n\nfunc (h *Host) executorAdapterForPlugin(pluginID string) (*executorAdapter, error) {\n\tif h == nil {\n\t\treturn nil, fmt.Errorf(\"plugin host is unavailable\")\n\t}\n\tpluginID = strings.TrimSpace(pluginID)\n\tif pluginID == \"\" {\n\t\treturn nil, fmt.Errorf(\"target executor plugin id is required\")\n\t}\n\tfor _, record := range h.activeRecords() {\n\t\tif record.id != pluginID {\n\t\t\tcontinue\n\t\t}\n\t\tif h.isPluginFused(record.id) {\n\t\t\treturn nil, fmt.Errorf(\"plugin executor %s is unavailable\", pluginID)\n\t\t}\n\t\texecutor := record.plugin.Capabilities.Executor\n\t\tif executor == nil {\n\t\t\treturn nil, fmt.Errorf(\"plugin %s does not declare an executor\", pluginID)\n\t\t}\n\t\tprovider, okProvider := h.executorProvider(record, executor)\n\t\tif !okProvider {","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/pluginhost/executor_route.go#L96-L132","documentation":"executorAdapterForPlugin returns this when the receiver Host itself is nil. It is a programming/lifecycle error: caller invoked CountPluginExecutor/ExecutePluginExecutor-style routing on a nil *Host, typically because the plugin host was never initialized in this process or was already torn down and the pointer zeroed.","triggerScenarios":"Calling Host.CountPluginExecutor (or the execute route that uses executorAdapterForPlugin) on a nil host pointer: embedding code that skips plugin host setup but still routes model requests to plugin executors, or a code path that reads the host from an optional field that was never set.","commonSituations":"Custom embeddings that treat the plugin host as optional; races during shutdown where the host reference is cleared while a request is being routed; tests constructing partial service objects.","solutions":["Ensure the plugin host is created and attached to the service before any request can be routed to a plugin executor.","Guard call sites: skip plugin-executor routing when the host is nil rather than calling into it.","If using official cmd/server, report a bug — this state should not be reachable there."],"exampleFix":"// before\nadapter, err := host.executorAdapterForPlugin(pluginID) // host may be nil\n\n// after\nif host == nil {\n\treturn nil, fmt.Errorf(\"plugin routing requested but plugin host is not initialized\")\n}\nadapter, err := host.executorAdapterForPlugin(pluginID)","handlingStrategy":"type-guard","validationCode":"if host == nil {\n    return fmt.Errorf(\"plugin executor routing skipped: plugin host not initialized\")\n}","typeGuard":"func pluginHostReady(h *pluginhost.Host) bool {\n    return h != nil\n}","tryCatchPattern":"// Go: defend with a nil-receiver check rather than catch\nif h == nil {\n    return coreexecutor.Response{}, fmt.Errorf(\"plugin host unavailable\")\n}\nresp, err := h.CountPluginExecutor(ctx, pluginID, req, opts)","preventionTips":["Make plugin host initialization mandatory before wiring executor routes.","Fail service startup if plugin-dependent routes exist but the host is nil."],"tags":["plugin","nil-check","lifecycle","executor","pluginhost"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}