router-for-me/CLIProxyAPI · error

model execution failed

Error message

model execution failed

What it means

The catch-all branch of modelExecutionError: the executor returned a non-nil ErrorMessage with neither an Error object nor a positive status code. The nested model call failed, but the executor gave no structured detail, so the host can only report generic failure to the plugin.

Source

Thrown at internal/pluginhost/host_callbacks.go:319

		Headers:                 cloneHeader(req.Headers),
		Query:                   cloneValues(req.Query),
		Alt:                     req.Alt,
		SkipInterceptorPluginID: skipPluginID,
		SkipRouterPluginID:      skipPluginID,
	}
}

func modelExecutionError(errMsg *interfaces.ErrorMessage) error {
	if errMsg == nil {
		return nil
	}
	if errMsg.Error != nil {
		return errMsg.Error
	}
	if errMsg.StatusCode > 0 {
		return fmt.Errorf("model execution failed with status %d", errMsg.StatusCode)
	}
	return fmt.Errorf("model execution failed")
}

func (h *Host) callHostLog(ctx context.Context, request []byte) ([]byte, error) {
	var req rpcHostLogRequest
	if errUnmarshal := json.Unmarshal(request, &req); errUnmarshal != nil {
		return nil, fmt.Errorf("decode host log request: %w", errUnmarshal)
	}
	ctx = h.resolveCallbackContext(req.HostCallbackID, ctx)
	message := strings.TrimSpace(req.Message)
	if message == "" {
		message = "plugin log"
	}
	fields := log.Fields{}
	for key, value := range req.Fields {
		key = strings.TrimSpace(key)
		if key != "" {
			fields[key] = value
		}

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Enable debug logging around the nested call to see which executor produced the empty ErrorMessage.
  2. If you own the executor/plugin code, always set either Error or StatusCode on failures instead of an empty ErrorMessage.
  3. Retry once to rule out a transient canceled execution; if reproducible, inspect the executor's failure paths.
  4. Update executor plugin and host to matching versions.

Example fix

// executor/plugin side, before
return resp, interfaces.ErrorMessage{} // failure with no detail

// after
return resp, interfaces.ErrorMessage{StatusCode: http.StatusBadGateway, Error: fmt.Errorf("upstream call failed")}
Defensive patterns

Strategy: retry

Type guard

func detailedModelError(errMsg *interfaces.ErrorMessage) bool {
    return errMsg != nil && (errMsg.Error != nil || errMsg.StatusCode > 0)
}

Try / catch

resp, err := host.ModelExecute(ctx, req)
if err != nil && strings.Contains(err.Error(), "model execution failed") && !strings.Contains(err.Error(), "status") {
    // detail-less failure: single retry to rule out a transient abort, then report upstream
    return retryOnceThenReport(ctx, req, err)
}

Prevention

When it happens

Trigger: host.model.execute returning an ErrorMessage with all fields zero: an executor implementation bug, an aborted/canceled execution reported without status, or an internal path that builds ErrorMessage{} without filling cause or code.

Common situations: Custom executor plugins that signal failure with an empty ErrorMessage; race where execution is canceled mid-flight and the error is assembled incompletely; version skew between executor interface expectations.

Related errors


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