router-for-me/CLIProxyAPI · error
ExecuteModel requires Stream=false
Error message
ExecuteModel requires Stream=false
What it means
Programmer error in the plugin/host model API: ExecuteModel() only performs non-streaming internal model requests, so calling it with ModelExecutionRequest{Stream: true} is rejected immediately with a mode error before any dispatch. The streaming counterpart is ExecuteModelStream().
Source
Thrown at sdk/api/handlers/model_execution.go:99
// Error returns the stream error message or the HTTP status text.
func (e *ModelExecutionStreamError) Error() string {
if e == nil {
return ""
}
if e.Message != "" {
return e.Message
}
return http.StatusText(e.StatusCode)
}
// ExecuteModel executes an internal non-streaming model request.
// Host model callbacks are non-recursive for their caller: when
// skip plugin IDs are set, that plugin's interceptors and router are skipped
// for the nested model execution while other plugins may still run.
func (h *BaseAPIHandler) ExecuteModel(ctx context.Context, req ModelExecutionRequest) (ModelExecutionResponse, *interfaces.ErrorMessage) {
if req.Stream {
return ModelExecutionResponse{}, modelExecutionModeError("ExecuteModel requires Stream=false")
}
body, headers, errMsg := h.executeWithAuthManagerFormats(ctx, req.EntryProtocol, req.ExitProtocol, req.Model, cloneBytes(req.Body), req.Alt, false, modelExecutionOptions{
Headers: req.Headers,
Query: req.Query,
InternalSource: true,
SkipInterceptorPluginID: req.SkipInterceptorPluginID,
SkipRouterPluginID: req.SkipRouterPluginID,
})
if errMsg != nil {
return ModelExecutionResponse{}, errMsg
}
return ModelExecutionResponse{
StatusCode: http.StatusOK,
Headers: cloneHeader(headers),
Body: cloneBytes(body),
}, nil
}
View on GitHub (pinned to 78f0c4079e)
Solutions
- Set Stream: false in the request, or remove the field (zero value is false)
- If you actually need chunks, call ExecuteModelStream with Stream: true instead
Example fix
// before
resp, errMsg := h.ExecuteModel(ctx, ModelExecutionRequest{Model: name, Body: body, Stream: true})
// after
resp, errMsg := h.ExecuteModel(ctx, ModelExecutionRequest{Model: name, Body: body, Stream: false}) Defensive patterns
Strategy: validation
Validate before calling
if req.Stream {
return nil, fmt.Errorf("use ExecuteModelStream for streaming; got Stream=true on ExecuteModel")
}
resp, errMsg := h.ExecuteModel(ctx, req) Type guard
func isNonStreamingExecution(req ModelExecutionRequest) bool {
return !req.Stream
} Try / catch
// Error is returned in-band via *interfaces.ErrorMessage, not a Go error:
resp, errMsg := h.ExecuteModel(ctx, req)
if errMsg != nil && strings.Contains(errMsg.Error(), "requires Stream=false") {
log.Error("programmer error: passed a streaming request to ExecuteModel")
} Prevention
- Construct ModelExecutionRequest next to the call site with the matching Stream value
- Enforce the pairing in code review: ExecuteModel<->false, ExecuteModelStream<->true
- Add unit tests asserting mode errors fire for mismatched Stream flags
When it happens
Trigger: A plugin or internal caller constructs a ModelExecutionRequest with Stream: true and passes it to BaseAPIHandler.ExecuteModel.
Common situations: Porting code between the streaming and non-streaming variants; copy-paste of a request struct that was originally built for the stream API.
Related errors
- ExecuteModelStream requires Stream=true
- ExecuteProtocolWithAuthManager requires Stream=false
- ExecuteProtocolStreamWithAuthManager requires Stream=true
- plugin sync response is nil
- count must be a positive integer
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/18b4cc0ddfa2b7e3.
Report an issue: GitHub.