{"record":{"id":"305e8c4c523a1d94","repo":"JuliusBrussee/caveman","slug":"contents-w","errorCode":null,"errorMessage":"contents: %w","messagePattern":"contents: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/pixel/transform_gemini.go","lineNumber":244,"sourceCode":"\tif opts.PriorWarmImageTokens > 0 {\n\t\tdef.PriorWarmImageTokens = opts.PriorWarmImageTokens\n\t}\n\tif opts.KeepSharp != nil {\n\t\tdef.KeepSharp = opts.KeepSharp\n\t}\n\tdef.EmitRecoverable = opts.EmitRecoverable\n\treturn def\n}\n\nfunc parseGeminiGenerateContent(body []byte) (geminiGenerateContent, error) {\n\tvar raw map[string]json.RawMessage\n\tif err := json.Unmarshal(body, &raw); err != nil {\n\t\treturn geminiGenerateContent{}, err\n\t}\n\treq := geminiGenerateContent{extra: raw}\n\tif v, ok := raw[\"contents\"]; ok {\n\t\tif err := json.Unmarshal(v, &req.Contents); err != nil {\n\t\t\treturn geminiGenerateContent{}, fmt.Errorf(\"contents: %w\", err)\n\t\t}\n\t}\n\tif v, ok := raw[\"systemInstruction\"]; ok && len(bytes.TrimSpace(v)) > 0 && !bytes.Equal(bytes.TrimSpace(v), []byte(\"null\")) {\n\t\tvar inst geminiInstruction\n\t\tif err := json.Unmarshal(v, &inst); err != nil {\n\t\t\treturn geminiGenerateContent{}, fmt.Errorf(\"systemInstruction: %w\", err)\n\t\t}\n\t\treq.SystemInstruction = &inst\n\t}\n\tif v, ok := raw[\"tools\"]; ok {\n\t\tif err := json.Unmarshal(v, &req.Tools); err != nil {\n\t\t\treturn geminiGenerateContent{}, fmt.Errorf(\"tools: %w\", err)\n\t\t}\n\t}\n\treturn req, nil\n}\n\nfunc geminiGlobalMediaResolution(raw map[string]json.RawMessage) (string, bool) {","sourceCodeStart":226,"sourceCodeEnd":262,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/engine/pixel/transform_gemini.go#L226-L262","documentation":"parseGeminiGenerateContent extracts the \"contents\" field from a Gemini GenerateContent request body and unmarshals it into req.Contents. If the value exists but does not match the expected geminiContent[] shape (wrong types, non-array, unexpected fields), the json.Unmarshal error is wrapped as \"contents: %w\" and TransformGemini fails.","triggerScenarios":"TransformGemini receiving a request body whose \"contents\" is not an array of valid content parts — e.g. a string instead of an array, an object where parts have unexpected types, or null-typed fields where structured values are required.","commonSituations":"Proxying hand-crafted Gemini requests with malformed contents; a client SDK version emitting a schema the transform does not recognize; test fixtures with truncated or hand-edited contents arrays.","solutions":["Validate the request body against the Gemini GenerateContent schema; ensure \"contents\" is an array of {role, parts:[...]} objects.","Inspect the wrapped %w error to find the exact JSON offset/type mismatch reported by encoding/json.","Update the client SDK or fix the fixture so parts use supported fields (text, inline_data, functionResponse, etc.)."],"exampleFix":"// before\n{\"contents\": \"hello\"}\n// after\n{\"contents\": [{\"role\": \"user\", \"parts\": [{\"text\": \"hello\"}]}]}","handlingStrategy":"validation","validationCode":"var probe struct {\n    Contents []json.RawMessage `json:\"contents\"`\n}\nif err := json.Unmarshal(body, &probe); err != nil {\n    return fmt.Errorf(\"contents must be an array of content objects\")\n}","typeGuard":"func validContents(raw map[string]json.RawMessage) bool {\n    v, ok := raw[\"contents\"]\n    if !ok {\n        return true\n    }\n    var arr []map[string]json.RawMessage\n    return json.Unmarshal(v, &arr) == nil\n}","tryCatchPattern":"req, err := parseGeminiGenerateContent(body)\nif err != nil {\n    var ue *json.UnmarshalTypeError\n    if errors.As(err, &ue) {\n        return fmt.Errorf(\"contents field type mismatch at %s: %w\", ue.Field, err)\n    }\n    return err\n}","preventionTips":["Validate request bodies against the Gemini GenerateContent schema before transforming.","Generate payloads with marshaling rather than string templates.","Read the wrapped %w error — encoding/json reports the exact field and Go type that mismatched.","Pin client SDK versions and re-check fixtures after upgrades."],"tags":["gemini","json","request-transform","schema"],"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"}