Repository navigation
[BUG]: Gemini 3 Pro function calling fails - missing thoughtSignature support #4832
Description
Activity
github-actions commented
on Nov 27, 2025 on Nov 27, 2025 – with GitHub ActionsContributorMore actionsThis issue might be a duplicate of existing issues. Please check:
- Could not use model "Gemini 3 Pro Preview" of Github copilot provider: "invalid request body" #4816: "Could not use model "Gemini 3 Pro Preview" of Github copilot provider: "invalid request body"" - Reports Gemini 3 tool calling failures with invalid request body errors in OpenCode
- tool_use
ids were found withouttool_result` blocks #4802: "tool_useids were found withouttool_resultblocks" - Related to tool use/function calling message structure issues across multiple models
Both issues indicate problems with how OpenCode handles function calling/tool use responses from LLM providers, which is the core issue described here regarding
thoughtSignaturehandling.Feel free to ignore if none of these address your specific case.
I can't replicate issue with your reproduction steps
@rekram1-node i think this happens when using gemini 3 pro with openrouter
what version of OC are you using
I suggest using this method first. langgenius/dify-official-plugins#2120
@rekram1-node i am using the latest version 1.0.141. The error i get is:
{"code":400,"message":"Provider returned error","type":null,"param":null,"metadata":{"raw":"{\n "error": {\n "code": 400,\n "message": "Corrupted thought signature.",\n "status": "INVALID_ARGUMENT"\n }\n}\n","provider_name":"Google AI Studio"}}@andreigiura under what circumstances? Any reproduction steps?
@rekram1-node i have tried to build a hello world app. then tried to enhence its design. it builds the hello world with react for example, but at some point it fails and never recover. just need to work with it a little bit in order to reproduce it. it only happes on openrouter provider, not directly with google gemini
Oh well that makes sense then
OpenRouter just did some bug fixes for their provider and I merged their fix in today. it will be in next release
Reacted by andreigiura and Dan Brown@rekram1-node have you got a link to the changes? I've just jumped to the latest release and I'm still seeing this issue
@matthewijordan you are encountering issues with gemini specifically through openrouter? Can you explain steps to reproduce?
here is one of the last fixes they did:
OpenRouterTeam/ai-sdk-provider#288Not sure if related at all, but when using Zen + Gemini 3 Pro I get
Request contains an invalid argument.on every request 🤔
Not sure where logs would get stored, but lemme know if I can provide more info?8 remaining items
I am also getting the same error. Version 1.2.6 with Google Gemini Pro and Flash using OpenRouter. No external plugins or anything, vanilla OpenCode config.
This is what I can see from the logs:
{ "error": { "code": 400, "message": "Unable to submit request because Thought signature is not valid.. Learn more: https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/gemini", "status": "INVALID_ARGUMENT" } }Anyone got an update on this? Seems it should have been fixed?
Reacted by Samwise Wang, Max Rohde, Vitor José Naidek, Brian, Long and Rui RamosI am also receiving this error when using gemini-3-flash-preview through the ollama cloud. I did not encounter the same issue with other ollama models.
I am also getting the same error. Version 1.2.6 with Google Gemini Pro and Flash using OpenRouter. No external plugins or anything, vanilla OpenCode config.
This is what I can see from the logs:
{ "error": { "code": 400, "message": "Unable to submit request because Thought signature is not valid.. Learn more: https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/gemini", "status": "INVALID_ARGUMENT" } }Anyone got an update on this? Seems it should have been fixed?
I am also receiving the same issue with Gemini models on OpenRouter.
Reacted by Zane Hitchcox and LongSame problem with Google Vertex AI with Gemini 3.1 Pro Preview
I just used very fewskillsfrom Claude. No other additional plugins were used.Unable to submit request because function call
default_api:readin the 73. content block is missing athought_signature. Learn more: https://docs.cloud.google.com/vertex-ai/generative-ai/docs/thought-signaturesReacted by RcINSSame issue with Vertex Gemini 3.1 Pro Preview on clean opencode installation
Reacted by Gintas Z. and PandaIsGoodSame issue, still getting a whole bunch of random thought signature errors on opencode 1.4.3, at least 20 times today, gemini 3.1 pro preview on openrouter.
Still having the same issue at latest version1.14.33. I'm using gemini over my own proxy on my server, which I believe all content has been routed to the gemini server. I myself would not change the json content.
openrouter sdk had bugs we updated sdk recently.
For ur custom one kinda need more info for ur proxy
@rekram1-node
well, it's a really simple proxy. I can just paste part of my source code here:func main() { // Parse a default target for the proxy constructor defaultTarget, err := url.Parse(targetLLMServerURL) if err != nil { log.Fatalf("FATAL: Failed to parse default target URL: %v", err) } proxy := httputil.NewSingleHostReverseProxy(defaultTarget) // 3. Customize the proxy's Director // The Director modifies the request *before* it's sent to the target. originalDirector := proxy.Director proxy.Director = func(r *http.Request) { // Run the original director logic (sets up scheme, host, etc.) originalDirector(r) // Read the full request body and replace it so it can be read again by the proxy. bodyBytes, err := io.ReadAll(r.Body) if err != nil { log.Printf("ERROR: Failed to read request body: %v", err) // leave request as-is; proxy will attempt to forward whatever remains return } // Close original and set a new ReadCloser for downstream _ = r.Body.Close() r.Body = io.NopCloser(bytes.NewReader(bodyBytes)) r.ContentLength = int64(len(bodyBytes)) r.Header.Set("Content-Length", strconv.Itoa(len(bodyBytes))) // Try to parse model from JSON body var reqData map[string]interface{} if len(bodyBytes) > 0 { if err := json.Unmarshal(bodyBytes, &reqData); err != nil { log.Printf("WARN: Failed to unmarshal request body; using default target: %v", err) } } // Determine target URL based on model (fallback to default) targetURL := defaultTarget if modelVal, ok := reqData["model"].(string); ok { targetURL = getUrl(modelVal) } else { log.Printf("INFO: 'model' field not found or not a string; using default target") } // Update request URL/host to route to selected target r.URL.Scheme = targetURL.Scheme r.URL.Host = targetURL.Host // Use the target's path as the request path (so full paths like /v1/chat/completions are honored) r.URL.Path = targetURL.Path r.Host = targetURL.Host // (Optional) If the target server needs a *different* API key, // you can swap it out here. if targetServerAPIKey != "" { r.Header.Set("Authorization", "Bearer "+targetServerAPIKey) } // If targetServerAPIKey is empty, the client's original // Authorization header is passed through automatically. log.Printf("Proxying request to: %s", targetURL.String()) } // 4. Define our main handler http.HandleFunc("/chat/completions", authAndProxyHandler(proxy)) // 5. Start the HTTP server log.Printf("Starting HTTP proxy server on http://localhost%s", serverAddr) log.Printf("Proxying requests to %s", targetLLMServerURL) log.Printf("Expecting 'Authorization: Bearer %s'", validClientAuthToken) err = http.ListenAndServe(serverAddr, nil) if err != nil { log.Fatalf("FATAL: Failed to start server: %v", err) } } // authAndProxyHandler returns a handler that first checks authentication // and then proxies the request if auth is successful. func authAndProxyHandler(proxy *httputil.ReverseProxy) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // --- 1. Method Check --- if r.Method != http.MethodPost && r.Method != http.MethodOptions { log.Printf("REJECT: Invalid method: %s", r.Method) http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } // --- 2. Auth Check --- authHeader := r.Header.Get("Authorization") if authHeader == "" { log.Println("REJECT: Missing Authorization header") http.Error(w, "Authorization header required", http.StatusUnauthorized) return } // Check for "Bearer <token>" format tokenParts := strings.Split(authHeader, " ") if len(tokenParts) != 2 || strings.ToLower(tokenParts[0]) != "bearer" { log.Println("REJECT: Invalid Authorization header format") http.Error(w, "Invalid Authorization header format", http.StatusUnauthorized) return } token := tokenParts[1] // Validate the token if token != validClientAuthToken { log.Println("REJECT: Invalid token") http.Error(w, "Invalid token", http.StatusForbidden) return } log.Printf("ACCEPT: Auth successful. Proxying request for %s", r.RemoteAddr) // --- 3. Proxy the Request --- // If auth is OK, let the proxy handle the rest. // It forwards the request and streams back the response. proxy.ServeHTTP(w, r) } }
the content of http request would never be changed
Have this been fixed?
Reacted by rmbusddollarif ur still having the issue send me a session u got it in?
opencode export > session.json- added a commit that references this issue
on May 16, 2026 Still get this issue, latest version of opencode and 3.5 flash.
@cyberfox1 As the msg above states, plz:
if ur still having the issue send me a session u got it in? opencode export > session.json
@cyberfox1 As the msg above states, plz:
if ur still having the issue send me a session u got it in? opencode export > session.json
I looked into this a bit more it seems my provider had switched from google to openai-compatible, switching it back to google resolved it.
[BUG]: Gemini 3 Pro function calling fails - missing
thoughtSignaturesupportDescription
When using Gemini 3 Pro models (
gemini-3-pro-preview) with function calling/tool use, requests fail with error:Root Cause
Gemini 3 Pro requires
thoughtSignatureto be preserved and passed back during multi-step function calling. This is a mandatory validation introduced in Gemini 3 (unlike Gemini 2.5 where it was optional).How Gemini 3 Thought Signatures Work
functionCall, it includes athoughtSignaturefieldfunctionResponseReference: https://ai.google.dev/gemini-api/docs/thought-signatures
Expected Flow
Current Behavior in OpenCode
OpenCode does not preserve
thoughtSignaturefrom Gemini API responses when building subsequent requests in conversation history.The
contentsarray in requests to Gemini API is missing thethoughtSignaturefield infunctionCallparts.Affected Models
gemini-3-pro-preview(mandatory - will error)gemini-2.5-pro/gemini-2.5-flash(optional but recommended for reasoning quality)Proposed Fix
Option 1: Preserve thoughtSignature in Message History
When storing model responses that contain
functionCallparts, also store thethoughtSignaturefield. When building the next request, include the signature in the corresponding content part:{ "contents": [ { "role": "model", "parts": [ { "functionCall": { "name": "webfetch", "args": {...} }, "thoughtSignature": "<preserved_signature>" // ← Add this } ] } ] }Option 2: Dummy Signature Workaround
According to Google's documentation, for cases where signatures cannot be preserved (e.g., transferring from another model), you can use dummy signatures:
or
This skips validation but may degrade reasoning quality.
Steps to Reproduce
gemini-3-pro-preview)Environment
gemini-3-pro-previewAdditional Context
Related Links