router-for-me/CLIProxyAPI · error
decode host log request: %w
Error message
decode host log request: %w
What it means
callHostLog failed to json.Unmarshal the RPC payload from the plugin into rpcHostLogRequest. This is a protocol-level failure: the plugin sent a host.log callback message whose JSON does not match the expected request shape (wrong field types, unknown structure, truncated bytes).
Source
Thrown at internal/pluginhost/host_callbacks.go:325
}
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
}
}
if requestID := logging.GetRequestID(ctx); requestID != "" {
fields["request_id"] = requestID
}
entry := log.WithFields(fields)
switch strings.ToLower(strings.TrimSpace(req.Level)) {View on GitHub (pinned to 78f0c4079e)
Solutions
- Rebuild/update the plugin against the same pluginhost/pluginapi version as the host so the log request schema matches.
- Inspect the wrapped json error (it names the field and offset) to see which key mismatches.
- In plugin code, only send simple types (string keys, scalar values) in Fields to stay schema-compatible.
- If framing corruption is suspected (random offsets), check the plugin transport logs for truncated messages.
Example fix
// plugin side, before
fields := map[string]any{"count": 42, "nested": struct{ A int }{1}} // unsupported shape
host.Log("msg", fields)
// after
fields := map[string]any{"count": 42} // scalars only
host.Log("msg", fields) Defensive patterns
Strategy: validation
Validate before calling
// Plugin side: keep log fields to scalars and validate before send
fields := map[string]any{}
for k, v := range raw {
switch v.(type) {
case string, float64, bool, nil:
fields[k] = v
default:
fields[k] = fmt.Sprintf("%v", v) // stringify anything else
}
} Type guard
func logFieldsRPCSafe(fields map[string]any) bool {
for k, v := range fields {
if strings.TrimSpace(k) == "" {
return false
}
switch v.(type) {
case string, float64, bool, nil:
default:
return false
}
}
return true
} Try / catch
if err := host.Log(message, fields); err != nil {
if strings.Contains(err.Error(), "decode host log request") {
// schema mismatch: fall back to plain message with no fields
_ = host.Log(message, nil)
}
} Prevention
- Ship plugin and host from the same build so RPC schemas match.
- Only send scalar values in log fields; marshal complex structs yourself to a string.
- Add a round-trip unit test for every host callback your plugin uses.
When it happens
Trigger: A plugin's host.log callback with mismatched JSON: Fields values of unexpected types, Message not a string, or a plugin built against a different rpcHostLogRequest schema. The error wraps the encoding/json failure with its position.
Common situations: Plugin and host compiled against different pluginhost RPC versions; a plugin marshaling a struct with incompatible field types; corrupted IPC framing producing invalid JSON.
Related errors
- auth file not found
- realtime_client_secret_capacity_exhausted
- invalid_session
- decode host auth list request: %w
- decode host auth get request: %w
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/ba4fb80c60fae772.
Report an issue: GitHub.