Skip to content

Gemini 3.1 Pro: malformed tool_use blocks cause 'command is required and must be a string' in Factory CLI #46

@anand-92

Description

@anand-92

Summary

When using Gemini 3.1 Pro (gemini-3.1-pro-preview) through DroidProxy, the Factory CLI (droid) rejects tool calls with:

Execute
    ↳ Error: command is required and must be a string

Claude (Opus 4.7) and other providers work fine from the same session — the issue is specific to Gemini's tool_use output.

Environment

  • DroidProxy v1.8.8 (macOS app bundle at ~/Applications/DroidProxy.app)
  • CLIProxyAPIPlus v6.9.28-0-plus running on 127.0.0.1:8318
  • ThinkingProxy on localhost:8317
  • Factory CLI (droid) as client
  • Model: gemini-3.1-pro-preview with thinking_level=high
  • macOS (darwin 25.4.0)

Reproduction

  1. Configure DroidProxy with Gemini 3.1 Pro at thinking level "high"
  2. Send a request from Factory CLI that should invoke the Execute tool
  3. Observe the CLI error: Execute → Error: command is required and must be a string

Observations from /tmp/droidproxy-debug.log

Proxy-side everything looks correct:

[2026-04-21T13:57:05Z] INCOMING REQUEST: POST /v1/messages
[2026-04-21T13:57:05Z] ORIGINAL BODY (first 500): {"model":"gemini-3.1-pro-preview","max_tokens":65536,...}
[2026-04-21T13:57:05Z] INJECTED Gemini thinking: level=high for model gemini-3.1-pro-preview
[2026-04-21T13:57:05Z] MODIFIED BODY (first 500): {"model":"gemini-3.1-pro-preview","generationConfig":{"thinkingConfig":{"thinking_level":"high"}},...}
[2026-04-21T13:57:05Z] THINKING INJECTED: true
  • Request is well-formed
  • generationConfig.thinkingConfig.thinking_level=high injected by ThinkingProxy.swift
  • No upstream HTTP errors logged (~/.cli-proxy-api/logs/ has no error files newer than Apr 18)
  • Both proxy ports (:8317, :8318) are live and healthy

The error is emitted by the Factory CLI when it parses a tool_use block whose input is missing the command field (or contains an empty/non-string value). This suggests Gemini is returning a function-call chunk that cli-proxy-api-plus translates into a tool_use with incomplete args.

Likely cause

One of:

  1. Gemini's SSE stream emits a partial functionCall chunk that the v1/messages translator forwards as a tool_use before the args are complete.
  2. Gemini hallucinates a call to Execute without populating the required command arg.
  3. The Gemini-to-Anthropic translation in cli-proxy-api-plus drops the arg when generationConfig.thinkingConfig.thinking_level=high changes the response shape (e.g., reasoning tokens interleaved with the tool call).

Next steps

  • Add response-body logging to ThinkingProxy (or tap cli-proxy-api-plus output) to capture the raw Gemini reply that produces the bad tool_use block
  • Try thinking_level=medium / low to check if the issue is triggered specifically by high reasoning
  • Check whether cli-proxy-api-plus needs an update that better handles interleaved reasoning + function-call chunks for Gemini 3.1
  • Consider emitting the tool_use block only after the full functionCall args JSON has been received

Workaround

Switch to Claude (Opus 4.7) or another provider. Gemini is effectively unusable for tool-driven sessions until the malformed tool_use is fixed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions