{"record":{"id":"2b7b7b2e21a662ce","repo":"JuliusBrussee/caveman","slug":"functionresponse-w","errorCode":null,"errorMessage":"functionResponse: %w","messagePattern":"functionResponse: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/pixel/transform_gemini.go","lineNumber":365,"sourceCode":"\tp.Extra = raw\n\tif v, ok := raw[\"text\"]; ok {\n\t\tvar s string\n\t\tif err := json.Unmarshal(v, &s); err != nil {\n\t\t\treturn fmt.Errorf(\"text: %w\", err)\n\t\t}\n\t\tp.Text = &s\n\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}","sourceCodeStart":347,"sourceCodeEnd":383,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/engine/pixel/transform_gemini.go#L347-L383","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"// before\nparts: [{functionResponse: 'result text'}]\n// after\nparts: [{functionResponse: {name: 'lookup', response: {result: 'ok'}}}]","handlingStrategy":"validation","validationCode":"func validFunctionResponse(p map[string]any) bool {\n  fr, ok := p[\"functionResponse\"].(map[string]any)\n  return !ok || (fr[\"name\"] != nil && fr[\"response\"] != nil)\n}","typeGuard":"func isMap(v json.RawMessage) bool { var m map[string]json.RawMessage; return json.Unmarshal(v, &m) == nil }","tryCatchPattern":"if err := json.Unmarshal(data, &part); err != nil {\n  if strings.HasPrefix(err.Error(), \"functionResponse:\") {\n    // log raw part JSON and skip or reject\n  }\n}","preventionTips":["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"],"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"}