{"record":{"id":"2d17b9f97b91294c","repo":"router-for-me/CLIProxyAPI","slug":"host-model-executor-is-unavailable","errorCode":null,"errorMessage":"host model executor is unavailable","messagePattern":"host model executor is unavailable","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/pluginhost/host_callbacks.go","lineNumber":279,"sourceCode":"\tvar req rpcStreamCloseRequest\n\tif errUnmarshal := json.Unmarshal(request, &req); errUnmarshal != nil {\n\t\treturn nil, fmt.Errorf(\"decode stream close request: %w\", errUnmarshal)\n\t}\n\th.streams.close(req.StreamID, req.Error)\n\treturn marshalRPCResult(rpcEmptyResponse{})\n}\n\nfunc (h *Host) callHostModelExecute(ctx context.Context, request []byte) ([]byte, error) {\n\tvar req rpcHostModelExecutionRequest\n\tif errUnmarshal := json.Unmarshal(request, &req); errUnmarshal != nil {\n\t\treturn nil, fmt.Errorf(\"decode host model execution request: %w\", errUnmarshal)\n\t}\n\tif req.Stream {\n\t\treturn nil, fmt.Errorf(\"host.model.execute requires stream=false\")\n\t}\n\texecutor := h.currentModelExecutor()\n\tif executor == nil {\n\t\treturn nil, fmt.Errorf(\"host model executor is unavailable\")\n\t}\n\tskipPluginID := h.callbackCallerPluginID(ctx, req.HostCallbackID)\n\tctx = h.resolveCallbackContext(req.HostCallbackID, ctx)\n\tresp, errMsg := executor.ExecuteModel(ctx, modelExecutionRequestFromPlugin(req.HostModelExecutionRequest, skipPluginID))\n\tif errMsg != nil {\n\t\treturn nil, modelExecutionError(errMsg)\n\t}\n\treturn marshalRPCResult(pluginapi.HostModelExecutionResponse{\n\t\tStatusCode: resp.StatusCode,\n\t\tHeaders:    cloneHeader(resp.Headers),\n\t\tBody:       append([]byte(nil), resp.Body...),\n\t})\n}\n\nfunc modelExecutionRequestFromPlugin(req pluginapi.HostModelExecutionRequest, skipPluginID string) handlers.ModelExecutionRequest {\n\treturn handlers.ModelExecutionRequest{\n\t\tEntryProtocol:           req.EntryProtocol,\n\t\tExitProtocol:            req.ExitProtocol,","sourceCodeStart":261,"sourceCodeEnd":297,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/pluginhost/host_callbacks.go#L261-L297","documentation":"During a host.model.execute callback from a plugin, the host asks its current model executor (h.currentModelExecutor()) to perform the upstream model call. If that returns nil — no executor is currently installed on the host — the callback fails with this error and the plugin's nested model call is rejected.","triggerScenarios":"A plugin invokes host.model.execute while the host has no current model executor: service still initializing, executor torn down during shutdown, or an embedded host configured without the model execution pipeline.","commonSituations":"Plugin performs a host-assisted model call during its own startup/registration before the executor is ready; embedding sdk/cliproxy without wiring the model executor; shutdown race where a plugin callback arrives after the executor was cleared.","solutions":["Defer plugin work that needs host.model.execute until the host signals readiness (executor installed).","In embeddings, wire the model executor into the host before loading plugins that use host model callbacks.","During shutdown, stop plugins (or their callbacks) before clearing the current model executor."],"exampleFix":"// plugin side, before\nfunc (p *Plugin) OnLoad(ctx context.Context) error {\n\t_, err := p.Host.ModelExecute(ctx, req) // executor may not be ready yet\n\treturn err\n}\n\n// after\nfunc (p *Plugin) OnReady(ctx context.Context) error {\n\t_, err := p.Host.ModelExecute(ctx, req) // host signals readiness first\n\treturn err\n}","handlingStrategy":"type-guard","validationCode":"// Plugin side: check readiness before host.model.execute\nif !host.ModelExecutorReady() {\n    return fmt.Errorf(\"host model executor not ready; defer this operation\")\n}","typeGuard":"func hostModelExecutionReady(h *pluginhost.Host) bool {\n    return h != nil && h.CurrentModelExecutor() != nil\n}","tryCatchPattern":"resp, err := host.ModelExecute(ctx, req)\nif err != nil && strings.Contains(err.Error(), \"host model executor is unavailable\") {\n    // retry after a readiness delay, or queue the work until host signals ready\n    return scheduleAfterReady(ctx, req)\n}","preventionTips":["Delay plugin initialization work needing host.model.execute until the host is fully started.","In embeddings, install the model executor before loading plugins."],"tags":["plugin","host-callback","executor","lifecycle","pluginhost"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}