{"record":{"id":"23860faf1154ab92","repo":"JuliusBrussee/caveman","slug":"functioncall-w","errorCode":null,"errorMessage":"functionCall: %w","messagePattern":"functionCall: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/pixel/transform_gemini.go","lineNumber":372,"sourceCode":"\t}\n\tif v, ok := raw[\"inline_data\"]; ok {\n\t\tvar inline geminiInlineData\n\t\tif err := json.Unmarshal(v, &inline); err != nil {\n\t\t\treturn fmt.Errorf(\"inline_data: %w\", err)\n\t\t}\n\t\tp.InlineData = &inline\n\t}\n\tif v, ok := raw[\"functionResponse\"]; ok {\n\t\tvar fr geminiFunctionResponse\n\t\tif err := json.Unmarshal(v, &fr); err != nil {\n\t\t\treturn fmt.Errorf(\"functionResponse: %w\", err)\n\t\t}\n\t\tp.FunctionResponse = &fr\n\t}\n\tif v, ok := raw[\"functionCall\"]; ok {\n\t\tvar fc geminiFunctionCall\n\t\tif err := json.Unmarshal(v, &fc); err != nil {\n\t\t\treturn fmt.Errorf(\"functionCall: %w\", err)\n\t\t}\n\t\tp.FunctionCall = &fc\n\t}\n\treturn nil\n}\n\nfunc (p geminiPart) MarshalJSON() ([]byte, error) {\n\traw := make(map[string]json.RawMessage, len(p.Extra)+4)\n\tfor k, v := range p.Extra {\n\t\traw[k] = v\n\t}\n\tif p.Text != nil {\n\t\tb, err := json.Marshal(*p.Text)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\traw[\"text\"] = b\n\t} else {","sourceCodeStart":354,"sourceCodeEnd":390,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/engine/pixel/transform_gemini.go#L354-L390","documentation":"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.","triggerScenarios":"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).","commonSituations":"Clients emitting functionCall as a string or array; model-output relayed verbatim with unexpected shape; schema drift between Gemini API versions.","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"],"exampleFix":"// before\nparts: [{functionCall: 'myTool'}]\n// after\nparts: [{functionCall: {name: 'myTool', args: {q: 'x'}}}]","handlingStrategy":"validation","validationCode":"func validFunctionCall(p map[string]any) bool {\n  fc, ok := p[\"functionCall\"].(map[string]any)\n  return !ok || (fc[\"name\"] != nil && (fc[\"args\"] == nil || isObject(fc[\"args\"])))\n}","typeGuard":"func isObject(v any) bool { _, ok := v.(map[string]any); return ok }","tryCatchPattern":"if err := json.Unmarshal(data, &part); err != nil {\n  if strings.HasPrefix(err.Error(), \"functionCall:\") {\n    // surface the raw functionCall JSON for inspection\n  }\n}","preventionTips":["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"],"tags":["json","gemini","unmarshal","transform"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}