JuliusBrussee/caveman · error
functionCall
Error message
functionCall: %w
What it means
During Gemini part JSON unmarshaling, the 'functionCall' key could not be decoded into geminiFunctionCall. The wrapper error names the field so callers can pinpoint which part of the Gemini payload is malformed. It signals an invalid functionCall object in the request.
Solutions
- Read the wrapped inner error to identify the exact type mismatch inside functionCall
- Ensure functionCall is an object with the fields geminiFunctionCall expects (e.g. name, args)
- Dump the raw JSON of the part to locate the malformed structure
- Fix the payload producer or converter to emit valid Gemini functionCall objects
Example fix
// before
parts: [{functionCall: 'myTool'}]
// after
parts: [{functionCall: {name: 'myTool', args: {q: 'x'}}}] Defensive patterns
Strategy: validation
Validate before calling
func validFunctionCall(p map[string]any) bool {
fc, ok := p["functionCall"].(map[string]any)
return !ok || (fc["name"] != nil && (fc["args"] == nil || isObject(fc["args"])))
} Type guard
func isObject(v any) bool { _, ok := v.(map[string]any); return ok } Try / catch
if err := json.Unmarshal(data, &part); err != nil {
if strings.HasPrefix(err.Error(), "functionCall:") {
// surface the raw functionCall JSON for inspection
}
} Prevention
- Always serialize functionCall as {name, args} objects
- Never relay raw model text without parsing it into the Gemini part schema
- Add schema validation on ingest of model-generated parts
When it happens
Trigger: UnmarshalJSON on a Gemini part where raw["functionCall"] exists but its JSON does not match geminiFunctionCall (e.g. missing name, args not an object, wrong types).
Common situations: Clients emitting functionCall as a string or array; model-output relayed verbatim with unexpected shape; schema drift between Gemini API versions.
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/23860faf1154ab92.
Report an issue: GitHub.
Appendix: source
Thrown at engine/pixel/transform_gemini.go:372
}
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
}
if p.Text != nil {
b, err := json.Marshal(*p.Text)
if err != nil {
return nil, err
}
raw["text"] = b
} else {View on GitHub (pinned to 3ee70a1026)