기본 콘텐츠로 건너뛰기

Gemini 3.7 Flash 400 Error? Fix Thinking Overflow

⚡ 3-Second Key Takeaways
Woke up to a wall of 400 INVALID_ARGUMENT errors after swapping your model string to gemini-3.7-flash? You're not alone. Since the August 13, 2026 GA release, a lot of production pipelines that quietly worked for months started throwing errors or silently truncating responses mid-JSON. The root cause almost never shows up in the error message itself — it's buried in how the new thinking-token budget interacts with your old generation_config. This is a debugging log from someone who spent an afternoon staring at finishReason: MAX_TOKENS before figuring out exactly what changed under the hood.

Why Your Old Config Suddenly Breaks

💡 Analogy: The Scratch Paper and the Exam Sheet Think of Gemini's "thinking" phase like an engineer's scratch paper before writing a final answer on the exam sheet. The model drafts, second-guesses, and re-derives the logic on that scratch paper — then copies the clean answer onto your response. Here's the catch with gemini-3.7-flash: the scratch paper and the exam sheet share the same page limit. Both draw from the same 65,536-token maxOutputTokens pool. If the model spends too many pages thinking, there's nothing left to write the actual answer, and the API cuts it off with MAX_TOKENS before a single character of your JSON reaches you.

That single design detail explains almost every ticket in the "Gemini 3.7 Flash suddenly broken" threads.

Root Cause #1: The THINKING_LEVEL_MINIMAL Trap

If your codebase (or a proxy layer like a self-hosted LiteLLM gateway) was written for older Flash-tier models, there's a good chance it still sends thinking_level: "minimal" or "none" to shave off latency. gemini-3.7-flash doesn't recognize either value. It only accepts three tiers:

thinking_level Typical Use Case Behavior on gemini-3.7-flash
low High-throughput chat, autocomplete, simple classification Minimal reasoning overhead, fastest response, closest to legacy "no thinking" behavior
medium (default) General agentic tasks, tool calling, coding assistants Balanced reasoning depth, recommended starting point
high Multi-step math, complex refactors, long-horizon planning Deepest reasoning chain, consumes the largest share of the output pool

Send anything outside this table — minimal, none, disable — and the API rejects the call outright with:

400 INVALID_ARGUMENT: Thinking level is unsupported: THINKING_LEVEL_MINIMAL
⚠️ No Silent Fallback
There's no silent fallback. It's a hard stop. The fix is mechanical: swap minimal for low, redeploy, done. But that alone doesn't solve the truncation problem — that's a separate, sneakier bug.

Root Cause #2: Output Token Starvation

Let's say you migrated your thinking_level correctly to "high" for a complex code-refactor agent, but you kept an old, conservative maxOutputTokens: 2048 from a previous cost-control pass. Here's what happens step by step:

Request sent (thinking_level=high, maxOutputTokens=2048)
        │
        ▼
Model starts internal reasoning
        │
        ▼
Reasoning tokens exceed 2048? ──── No ──▶ Reasoning completes ──▶ Full response returned
        │
       Yes
        │
        ▼
Token budget exhausted mid-thought
        │
        ▼
finishReason: MAX_TOKENS
        │
        ▼
Empty or truncated final response body

With thinking_level: "high", the model can easily burn 1,500–1,900 tokens just deliberating before it writes a single word of the actual answer. A 2,048 cap leaves almost no room, and you get an empty text field with a MAX_TOKENS finish reason — which looks like a network bug, not a config bug.

📌 Set a Realistic Budget, Not a Max Budget The fix isn't "always max out to 65,536." It's setting a realistic budget for the task. A quick JSON classification task at thinking_level: "low" rarely needs more than 4,096–8,192 total. A multi-step agentic coding task at "high" should get 16,384 or higher, or you should simply omit maxOutputTokens and let it default to the full 65,536 ceiling.

Step-by-Step Fix: Production Code

Below are drop-in configs for both the Python and Node.js SDKs. Pay close attention to what's removedtemperature, top_p, and top_k are deprecated for this model family and should not be manually overridden.

Python (google-genai)

from google import genai
from google.genai import types

# Initialize the client using your API key from environment variables.
client = genai.Client(api_key="YOUR_API_KEY")

# Define the generation config explicitly.
# Note: we do NOT set temperature, top_p, or top_k here.
# Gemini 3.7 Flash deprecates manual sampling overrides —
# leaving them at model defaults avoids decode-loop regressions.
config = types.GenerateContentConfig(
    # thinking_level must be one of: "low", "medium", "high".
    # "minimal" or "none" will raise a 400 INVALID_ARGUMENT error.
    thinking_config=types.ThinkingConfig(
        thinking_level="medium"
    ),
    # Give the model enough room for BOTH thinking AND the final answer.
    # 16384 is a safe floor for agentic / coding tasks.
    # Omit this field entirely to default to the full 65536 ceiling.
    max_output_tokens=16384,
    # Structured output is fine, just don't pair it with low token budgets.
    response_mime_type="application/json",
)

response = client.models.generate_content(
    model="gemini-3.7-flash",
    contents="Refactor this function to remove the nested loop and explain why.",
    config=config,
)

# Always check finish_reason before trusting response.text is complete.
if response.candidates[0].finish_reason == "MAX_TOKENS":
    print("Truncated! Increase max_output_tokens or lower thinking_level.")
else:
    print(response.text)

Node.js / TypeScript (@google/genai)

import { GoogleGenAI } from "@google/genai";

// API key is pulled from process.env.GEMINI_API_KEY by default.
const ai = new GoogleGenAI({});

async function runAgentTask() {
  // generationConfig mirrors the Python SDK structure.
  // thinkingConfig.thinkingLevel accepts only "low" | "medium" | "high".
  const response = await ai.models.generateContent({
    model: "gemini-3.7-flash",
    contents: "Summarize this 40-page PDF into 5 bullet points.",
    config: {
      thinkingConfig: {
        // "low" is ideal here since summarization doesn't need deep reasoning.
        thinkingLevel: "low",
      },
      // Even simple tasks need headroom; don't starve the output pool.
      maxOutputTokens: 8192,
      // No temperature/topP/topK overrides — leave sampling at model defaults.
    },
  });

  // Defensive check: log finishReason so truncation never fails silently.
  const finishReason = response.candidates?.[0]?.finishReason;
  if (finishReason === "MAX_TOKENS") {
    console.warn("Output was cut short — raise maxOutputTokens or lower thinkingLevel.");
  }

  console.log(response.text);
}

runAgentTask();

The pattern is consistent across both SDKs: pick a thinking_level that matches task complexity, give it a realistic token ceiling, and stop touching sampling parameters that no longer apply.

Advanced Troubleshooting: JSON Schema Loops

If you're forcing responseMimeType: "application/json" with a strict schema and you manually pinned temperature to something low like 0.2, watch for a specific failure mode: the model gets stuck re-generating the same digit or field repeatedly until it hits the token ceiling. This looks like an infinite loop but it's actually a decode conflict between the forced low-temperature sampling and the schema constraint solver.

📌 Migration Checklist: Moving Off an Older Flash Generation
  • ☑ Remove any explicit temperature, top_p, top_k values from generation_config
  • ☑ Replace thinking_level: "minimal" / "none" with "low"
  • ☑ Raise maxOutputTokens proportionally to thinking_level (low → 4k-8k, medium → 8k-16k, high → 16k+)
  • ☑ Add a finishReason check in your response handler — don't assume response.text is complete
  • ☑ Re-test structured JSON schema calls specifically; loop bugs rarely show up in plain-text prompts

If you're also comparing reasoning depth against other current-generation models like Claude Sonnet 5 or GPT-5.6 Sol for the same agentic workload, the same principle applies broadly: reasoning-heavy models need proportionally larger output budgets, not just longer prompts.

Wrapping Up

The 400 error is the easy part to fix — swap minimal for low and move on. The truncation bug is the one that actually costs you debugging hours, because it fails silently and looks like a network issue. Once you understand that thinking tokens and output tokens share one pool, the fix is just arithmetic: give the model enough room to think and answer.

💡 Keep Debugging Smarter If you're running a broader agent stack and want to see how token budgeting compares across other coding-focused tools, the English LLM & CODE guide archive has more production debugging write-ups in the same vein. Teams working across languages might also find it useful to cross-reference the Korean-language LLM & 코드 가이드 category for parallel API troubleshooting notes.

If this saved you from an afternoon of console-log archaeology, drop a comment with what error message you were hitting — it helps other developers hitting the same wall find the fix faster.

댓글

이 블로그의 인기 게시물

Gemini Many-Shot Prompting: Why 500 Examples Beat Fine-Tuning

No More Git Conflicts: Automate PR Reviews with Cline

기밀 유출 없는 DeepSeek R1 무료 로컬 실행법