Skip to content

fix: strip id field from FunctionCall/FunctionResponse before sending to Gemini API#973

Open
YuqiGuo105 wants to merge 1 commit intogoogleapis:mainfrom
YuqiGuo105:fix/strip-id-from-function-call-response
Open

fix: strip id field from FunctionCall/FunctionResponse before sending to Gemini API#973
YuqiGuo105 wants to merge 1 commit intogoogleapis:mainfrom
YuqiGuo105:fix/strip-id-from-function-call-response

Conversation

@YuqiGuo105
Copy link
Copy Markdown

Problem

Fixes #694

The Gemini API rejects requests that include an id field inside contents[].parts[].function_call or contents[].parts[].function_response, returning:

400 Invalid JSON payload received. Unknown name "id" at 'contents[5].parts[0].function_call': Cannot find field.
400 Invalid JSON payload received. Unknown name "id" at 'contents[6].parts[0].function_response': Cannot find field.

This surfaces in multi-turn / multi-agent workflows (e.g. Google ADK) where the SDK serializes FunctionCall and FunctionResponse objects that carry an id field populated from a previous model response. The field is valid on the inbound (model → client) side but is not accepted on the outbound (client → API) side.


Root Cause

The converter methods in the five converter files (Models, Batches, Caches, LiveConverters, TokensConverters) were copying every field from the type object into the outbound JSON, including id.

BeforefunctionCallToMldev in each converter copied id unconditionally:

// copied into outbound JSON — causes 400
if (Common.getValueByPath(fromObject, new String[] {"id"}) != null) {
  Common.setValueByPath(
      toObject,
      new String[] {"id"},
      Common.getValueByPath(fromObject, new String[] {"id"}));
}

BeforepartToMldev passed functionResponse through as-is (including id):

Common.setValueByPath(
    toObject,
    new String[] {"functionResponse"},
    Common.getValueByPath(fromObject, new String[] {"functionResponse"}));

Fix

After — the id copy-block is removed from functionCallToMldev in all five files.

AfterpartToMldev converts functionResponse to a JsonNode and explicitly removes id before forwarding:

JsonNode functionResponseNode =
    JsonSerializable.toJsonNode(
        Common.getValueByPath(fromObject, new String[] {"functionResponse"}));
if (functionResponseNode instanceof ObjectNode) {
  ((ObjectNode) functionResponseNode).remove("id");
}
Common.setValueByPath(toObject, new String[] {"functionResponse"}, functionResponseNode);

The id field is intentionally kept in FunctionCall.java and FunctionResponse.java so the SDK can still deserialize it from inbound model responses.


Files Changed

File Change
Models.java Remove id from functionCallToMldev; strip id in partToMldev
Batches.java Same
Caches.java Same (2 occurrences of partToMldev)
LiveConverters.java Same (2 occurrences of partToMldev)
TokensConverters.java Same
FunctionCallIdStrippingTest.java New test: 20 tests covering all 5 converters

Testing

Added FunctionCallIdStrippingTest.java with 20 JUnit 5 tests:

  • id is stripped from FunctionCall in all 5 converters
  • id is stripped from FunctionResponse in all 5 converters
  • Non-id fields (name, args, response) are preserved
  • FunctionCall/FunctionResponse type objects still deserialize id from JSON (regression guard)
  • Edge cases: no id present, name-only function call

All 20 tests pass.

…ng to Gemini API

The Gemini API does not accept an 'id' field in
contents[].parts[].function_call or
contents[].parts[].function_response, returning HTTP 400
'Unknown name id' when the field is present.

The SDK was forwarding the 'id' field from the FunctionCall and
FunctionResponse type objects directly into the outbound JSON payload
via the converter methods in Models, Batches, Caches, LiveConverters,
and TokensConverters.

Fix: remove the 'id' copy-block from functionCallToMldev() and strip
'id' from the functionResponse node in partToMldev() across all five
converter files. The 'id' field is intentionally retained in the type
definitions so it can still be deserialized from inbound API responses.

Fixes googleapis#694
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Function calls with 'id' fails with 400 using Gemini

1 participant