JuliusBrussee/caveman · error
functionResponse
Error message
functionResponse: %w
What it means
During Gemini part JSON unmarshaling, the 'functionResponse' key could not be decoded into the geminiFunctionResponse struct. The transform wraps the underlying json.Unmarshal error so the caller knows which Gemini part field failed. It indicates a malformed functionResponse object in the Gemini-format request payload.
Solutions
- Inspect the wrapped inner error to find the exact field/type mismatch in functionResponse
- Validate that functionResponse is an object with the fields geminiFunctionResponse expects before sending
- Log the raw JSON fragment around 'functionResponse' to spot malformed input
- Fix the producer of the payload (client, proxy, or converter) to emit valid Gemini functionResponse objects
Example fix
// before
parts: [{functionResponse: 'result text'}]
// after
parts: [{functionResponse: {name: 'lookup', response: {result: 'ok'}}}] Defensive patterns
Strategy: validation
Validate before calling
func validFunctionResponse(p map[string]any) bool {
fr, ok := p["functionResponse"].(map[string]any)
return !ok || (fr["name"] != nil && fr["response"] != nil)
} Type guard
func isMap(v json.RawMessage) bool { var m map[string]json.RawMessage; return json.Unmarshal(v, &m) == nil } Try / catch
if err := json.Unmarshal(data, &part); err != nil {
if strings.HasPrefix(err.Error(), "functionResponse:") {
// log raw part JSON and skip or reject
}
} Prevention
- Emit functionResponse as an object with name and response fields
- Validate payloads against the Gemini part schema before sending
- Log raw payloads when a transform fails to speed diagnosis
When it happens
Trigger: UnmarshalJSON on a Gemini part where raw["functionResponse"] exists but its JSON shape does not match geminiFunctionResponse (wrong types, missing/wrongly-typed fields like name or response).
Common situations: Hand-written or client-generated Gemini payloads with a functionResponse that isn't an object (e.g. a string or array); API version drift changing field types; proxies re-serializing tool results incorrectly.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/2b7b7b2e21a662ce.
Report an issue: GitHub.
Appendix: source
Thrown at engine/pixel/transform_gemini.go:365
p.Extra = raw
if v, ok := raw["text"]; ok {
var s string
if err := json.Unmarshal(v, &s); err != nil {
return fmt.Errorf("text: %w", err)
}
p.Text = &s
}
if v, ok := raw["inline_data"]; ok {
var inline geminiInlineData
if err := json.Unmarshal(v, &inline); err != nil {
return fmt.Errorf("inline_data: %w", err)
}
p.InlineData = &inline
}
if v, ok := raw["functionResponse"]; ok {
var fr geminiFunctionResponse
if err := json.Unmarshal(v, &fr); err != nil {
return fmt.Errorf("functionResponse: %w", err)
}
p.FunctionResponse = &fr
}
if v, ok := raw["functionCall"]; ok {
var fc geminiFunctionCall
if err := json.Unmarshal(v, &fc); err != nil {
return fmt.Errorf("functionCall: %w", err)
}
p.FunctionCall = &fc
}
return nil
}
func (p geminiPart) MarshalJSON() ([]byte, error) {
raw := make(map[string]json.RawMessage, len(p.Extra)+4)
for k, v := range p.Extra {
raw[k] = v
}View on GitHub (pinned to 3ee70a1026)