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.

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.

Appendix: 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)