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

  1. Inspect the wrapped inner error to find the exact field/type mismatch in functionResponse
  2. Validate that functionResponse is an object with the fields geminiFunctionResponse expects before sending
  3. Log the raw JSON fragment around 'functionResponse' to spot malformed input
  4. 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

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)