# Gemini 4 Argon API finish_reason: CONTINUATION and Empty Replies

> Gemini 4 Argon: resend with continuationToken on CONTINUATION, raise the budget when MAX_TOKENS has no text. OpenAI-compatible endpoints can't continue.

- URL: https://blog.laozhang.ai/en/posts/gemini-4-argon-api-finish-reason
- Published: 2026-10-28
- Updated: 2026-10-28
- Author: LaoZhang AI Team (https://blog.laozhang.ai/en/about)
- Topic: API Guides
- Tags: Gemini 4 Argon, Gemini API, finish_reason, Long Decode, Google GenAI SDK, Troubleshooting

---
Gemini 4 Argon (`gemini-4-argon`) cuts answers short for two ordinary reasons, and your code has to tell them apart. `CONTINUATION` means the model reached the per-request cap (65,536 output tokens, or 32,768 on a non-streaming REST call) with budget still left, so send the identical request again with the `continuationToken` it returned and repeat until the reason changes. `MAX_TOKENS` means the whole `maxOutputTokens` budget is gone, thinking included. If that reply has no text at all, every token went to thinking: raise `maxOutputTokens` to at least 32,768 or lower `thinkingLevel`.

Whether you ever see `CONTINUATION` depends on how you call Argon. Python `google-genai` 2.30.1+ and JavaScript `@google/genai` 2.29.1+ continue on the native `generateContent` endpoint by themselves and hand you one combined answer ending in `STOP`; older SDKs return the first, often empty, piece without raising an error. OpenAI-compatible endpoints, Google's included, cannot continue, and a gateway that drops `continuationToken` leaves you an empty answer with nothing to resume. For answers past 65,536 tokens, use a current SDK on the native endpoint, your own REST loop, or the Interactions API with `background: true`.

On October 28, 2026, Argon was called through one third-party gateway on its Gemini-native and OpenAI-compatible endpoints, and the Python SDK was run against a local mock server. No direct Google API key was used, and a real `CONTINUATION` never came back from that gateway, so statements about Google's direct behavior come from Google's [long decode guide for generateContent](https://ai.google.dev/gemini-api/docs/generate-content/long-decode) and the [Gemini API generateContent reference](https://ai.google.dev/api/generate-content).

## What each Gemini 4 Argon finish_reason means and what to do next

Continue only when the reason is `CONTINUATION` and a token came with it; every other value ends the loop and tells you what to change before the next request. The field is `finishReason` in REST JSON and `finish_reason` in the Python SDK and in OpenAI-style responses. Argon only outputs text, so the image reasons in the enum (`IMAGE_SAFETY`, `NO_IMAGE` and the rest) don't occur. The meanings below are from the [generateContent API reference](https://ai.google.dev/api/generate-content) and Google's long decode guide, as of October 28, 2026.

| finishReason | What it means on Argon | What your code does next |
| --- | --- | --- |
| `STOP` | The model ended on its own or hit a stop sequence | Treat as finished, but check that the text actually does the task |
| `CONTINUATION` with `continuationToken` | Per-request cap reached, budget left; the text can be empty because the hop was all thinking | Resend the identical request plus the latest token |
| `CONTINUATION` without a token | Something between you and Google dropped the field | You can't resume; call the native API directly or use Interactions with `background: true` |
| `MAX_TOKENS` with text | All of `maxOutputTokens` is used, thinking included | Direct from Google, the reply still carries a token: resend with it and a higher `maxOutputTokens`, or start over without it and pay for both runs |
| `MAX_TOKENS` with empty text | The whole budget went to thinking | Raise `maxOutputTokens` (32,768 at minimum) or lower `thinkingLevel` |
| No value, or an empty string, on the last stream chunk | The connection ended before the model did | Treat as incomplete; resume from the last checkpoint token or resend |
| `SAFETY`, `PROHIBITED_CONTENT`, `BLOCKLIST`, `SPII`, `RECITATION`, `LANGUAGE` | Content stop | Change the prompt or input; resending the same request won't help |
| `MALFORMED_FUNCTION_CALL`, `UNEXPECTED_TOOL_CALL`, `TOO_MANY_TOOL_CALLS`, `MISSING_THOUGHT_SIGNATURE`, `MALFORMED_RESPONSE` | Tool-call or response format problem | Fix tool declarations, enable tools you expect to be called, or send back the thought signatures you received |
| `ESCALATION`, `PUP_LIMITED_DISABLED` | Filtered by an escalation rule, or the account is limited for Prohibited Use Policy violations | Not a code fix; check the account and the content policy |
| `OTHER` | Unspecified | Log `finishMessage` and retry once |

![Decision chart for Gemini 4 Argon finish_reason: STOP, CONTINUATION with or without a token, MAX_TOKENS with or without text, and a missing reason, each leading to its next step](https://blog.laozhang.ai/posts/en/gemini-4-argon-api-finish-reason/img/finish-reason-decision.webp)

`STOP` only means the model stopped by itself, not that it did what you asked. In a test on October 28, Argon was asked to print every integer from 1 to 7,000 with a 33,000-token budget; it answered in 142 tokens that the list would exceed its output limit, suggested `seq 1 7000`, and ended with `STOP`. If your pipeline checks only the finish reason, that refusal passes as a success.

The same rules fit in one function that maps a REST response to a next step. This function and the `openai_truncated` check further down were run on October 28, 2026 against seven saved gateway responses and four hand-written cases; all eleven gave the expected result, including the empty-string reason on a cut stream.

```python
def next_action(resp):
    cands = resp.get("candidates") or []
    if not cands:
        return "prompt blocked or no candidate: log the body, fix the prompt"
    cand = cands[0]
    reason, token = cand.get("finishReason") or None, cand.get("continuationToken")
    parts = (cand.get("content") or {}).get("parts") or []
    text = "".join(p.get("text", "") for p in parts if not p.get("thought"))
    if reason is None:
        return "incomplete: no finishReason; resume from the last checkpoint token or resend"
    if reason == "STOP":
        return "done (still check that the text does the task)"
    if reason == "CONTINUATION":
        return "continue: resend with continuationToken" if token else \
               "token dropped: call the native API directly or use Interactions"
    if reason == "MAX_TOKENS":
        why = "empty, all thinking; " if not text else ""
        return why + ("raise maxOutputTokens, resend with token" if token else "raise maxOutputTokens, start over")
    if reason in {"SAFETY", "PROHIBITED_CONTENT", "BLOCKLIST", "SPII", "RECITATION", "LANGUAGE"}:
        return "content stop: change the prompt or input"
    if reason in {"MALFORMED_FUNCTION_CALL", "UNEXPECTED_TOOL_CALL", "TOO_MANY_TOOL_CALLS",
                  "MISSING_THOUGHT_SIGNATURE", "MALFORMED_RESPONSE"}:
        return "tool or format stop: fix tool declarations or return thought signatures"
    return f"other ({reason}): log finishMessage {cand.get('finishMessage')!r}, retry once"
```

## How to access the Gemini 4 Argon API: paid key, model ID, SDK version

Argon is a paid-tier model on the Gemini API: Google's [Gemini API pricing page](https://ai.google.dev/gemini-api/docs/pricing) lists it as not available on the free tier, and every token is billed, thinking tokens included. Most early cut-offs come from skipping one of the setup steps below, so check them in order before you debug finish reasons.

1. Put the Google Cloud project behind your key on a paid tier: link billing and prepay at least $5 for Tier 1. A free-tier key can't call Argon, and a key whose prepaid balance reaches $0 stops with HTTP 402.
2. Call the model ID `gemini-4-argon`, generally available since October 13, 2026 according to the [Gemini API changelog](https://ai.google.dev/gemini-api/docs/changelog).
3. Upgrade the SDK: `pip install -U "google-genai>=2.30.1"` or `npm install "@google/genai@>=2.29.1"` (Go 1.74.0, Java 1.77.0, .NET 1.26.0 and Kotlin 1.6.0 are the other minimums).
4. Set `max_output_tokens` to at least 32,768 for ordinary apps and above 65,536 for long answers. It's one total for thinking and output across every hop, and lowering it doesn't make thinking shorter, it only cuts the answer sooner.
5. Remove `temperature`, `top_p` and `top_k` (Argon ignores them), and set `thinking_level` to `low`, `medium` (the default) or `high`, never `minimal` and never together with `thinking_budget`. What each level changes is in [Gemini 3.1 Pro Thinking Levels: Low vs High, Defaults, Gemini 4](https://blog.laozhang.ai/en/posts/gemini-3-1-pro-thinking-level).
6. Set the HTTP read timeout to 20 minutes, for example `genai.Client(http_options=types.HttpOptions(timeout=1_200_000))` in Python. Google closes non-streaming calls after 10 minutes and streams after 20, and a 3- or 5-minute client timeout ends hard requests early.

A Google AI Pro or Ultra subscription doesn't switch on API calls for a project by itself; what the plans include for Argon in the app, AI Studio and API credits is covered in [Gemini 4 Argon Usage Limits: Pro vs Ultra, Resets, API Credits](https://blog.laozhang.ai/en/posts/gemini-4-argon-usage-limits). As of October 28, 2026, Argon costs $2 input and $10 output per million tokens until November 30, then $4 and $20 from December 1; the full price list is in [Gemini API Pricing 2026: Token Rates, Free Tier, and Key Cost](https://blog.laozhang.ai/en/posts/gemini-api-pricing). The API serves the United States, Japan, South Korea and Spain among others, but not mainland China, Hong Kong, Russia or Iran, per Google's [available regions list](https://ai.google.dev/gemini-api/docs/available-regions).

## Which Argon endpoints can continue an answer past 65,536 tokens

Only two setups produce a long Argon answer today: the native `generateContent` endpoint with someone running the continuation (a current SDK or your own loop), and the Interactions API with background execution. Google's long decode guide states that on the OpenAI compatibility endpoint "Long decode is not available. Output stops at the per-request cap." A gateway sits in front of one of these, so it can continue only if it passes `continuationToken` through in both directions.

| How you call Argon | Can it continue? | How the end is signaled |
| --- | --- | --- |
| `google-genai` ≥ 2.30.1 / `@google/genai` ≥ 2.29.1, native endpoint | Yes, automatically (`automatic_continuation` defaults to on) | One combined response; `finish_reason` of the last hop |
| Older SDK versions | No; output stops at 64K | `CONTINUATION` returned to you, no error |
| REST `generateContent` / `streamGenerateContent` | Yes, with your own loop (32K per non-streaming hop, 64K per stream) | `finishReason` on every hop |
| Interactions API, `background: true`, `store: true` | Yes, Google runs and joins the hops, for up to 24 hours | `status`: `completed`, `requires_action`, `incomplete`, `failed`, `cancelled` |
| Interactions API, `background: false` | No; 65,536 cap, larger values return 400 | `status` |
| OpenAI-compatible endpoint (`https://generativelanguage.googleapis.com/v1beta/openai/`) | No | `finish_reason`; Google doesn't document how it maps |
| Third-party gateway | Only if it forwards `continuationToken` | Whatever the gateway returns; see the tests below |

On Interactions there is no `finish_reason` to read. Per Google's [Interactions long decode guide](https://ai.google.dev/gemini-api/docs/long-decode), you create the interaction with `background: true` and `max_output_tokens` above 65,536, poll until the status leaves `in_progress` or `queued`, and handle `incomplete` the way you would handle `MAX_TOKENS`: the budget ran out, the text can be empty if the model was still thinking, and the fix is to resend with a higher `max_output_tokens`.

If you reach Argon through the OpenAI SDK, `reasoning_effort` maps to Argon's thinking levels on Google's endpoint, but long answers stay capped at one request. [OpenAI Base URL Override: Which Setting Wins and What to Paste](https://blog.laozhang.ai/en/posts/openai-base-url-override) covers pointing the OpenAI client at another endpoint.

## Why google-genai never shows you CONTINUATION

With `google-genai` 2.30.1 or later, `CONTINUATION` is handled inside the SDK: it sends the follow-up request, merges the parts, sums the usage and returns only the final reason. That's why a working setup almost never shows the value, and why seeing it in your logs usually means an old SDK or a gateway that lost the token. To confirm this without spending money, `google-genai` 2.33.0 (the latest on PyPI on October 28, 2026) and 2.29.0 were pointed at a local server that returned responses in the shape Google documents.

| Mock scenario | google-genai 2.33.0 | google-genai 2.29.0 |
| --- | --- | --- |
| Hop 1 `CONTINUATION` + token, empty text, 32,768 thinking tokens; hop 2 `STOP` | 2 requests; the second carried the token with the same `maxOutputTokens` (262,144) and the same contents. You get `STOP` and the final text | 1 request; you get `CONTINUATION`, empty text and the token, no exception |
| Same, with `automatic_continuation=False` | 1 request; you get `CONTINUATION` and the token | The option doesn't exist |
| `CONTINUATION` with no token, as from a gateway that strips it | 1 request; empty text and `CONTINUATION`, no exception | Same |
| `MAX_TOKENS` + token | 1 request; partial text and the token; the SDK does not continue | Same |

The third row is the failure to guard against: no exception, HTTP 200, and an empty `response.text`. The SDK source (`google/genai/_extra_utils.py` in 2.33.0) only resumes when the finish reason is `CONTINUATION` or missing, and on streams it gives up after three reconnects that bring no new checkpoint token. So after any Argon call, check `response.text` and `finish_reason` together, and treat empty text with `CONTINUATION` as a broken connection to Google rather than a short answer.

## Writing the continuation loop yourself over REST

If you call REST directly, or need the SDK's loop off (`automatic_continuation=False` in Python, `automaticContinuation: false` in JavaScript), the loop is short. The version below follows the rules in Google's long decode guide. On October 28, 2026 it was run against a local mock that returned two `CONTINUATION` hops and then `STOP`: it sent three requests with the same contents and the same `maxOutputTokens`, joined the text and kept the first hop's prompt count. It has not been run against Google's servers.

```python
import os
import requests

URL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-4-argon:generateContent"
HEADERS = {"x-goog-api-key": os.environ["GEMINI_API_KEY"], "Content-Type": "application/json"}

def run_long(prompt, max_output_tokens=262_144):
    body = {
        "contents": [{"role": "user", "parts": [{"text": prompt}]}],
        "generationConfig": {"maxOutputTokens": max_output_tokens, "thinkingConfig": {"thinkingLevel": "high"}},
    }
    parts, usage_sum, first_prompt = [], {}, None
    while True:
        r = requests.post(URL, headers=HEADERS, json=body, timeout=1200)  # 20-minute read timeout
        r.raise_for_status()
        data = r.json()
        cand = data["candidates"][0]
        usage = data.get("usageMetadata", {})
        if first_prompt is None:
            first_prompt = usage.get("promptTokenCount")  # your real prompt size
        for k, v in usage.items():
            if isinstance(v, int):
                usage_sum[k] = usage_sum.get(k, 0) + v  # each REST hop reports only itself
        parts += (cand.get("content") or {}).get("parts", [])
        token = cand.get("continuationToken")
        if cand.get("finishReason") != "CONTINUATION" or not token:
            break
        body["continuationToken"] = token  # same contents, same config, latest token only
    text = "".join(p.get("text", "") for p in parts if not p.get("thought"))
    return text, cand.get("finishReason"), first_prompt, usage_sum
```

Three rules from Google's guide matter more than the code. Send the original `contents`, `system_instruction`, `tools` and `generation_config` on every hop with the same `maxOutputTokens`, because the API reference requires the contents to "identically replicate" the first request. Never append the partial output to `contents`; the token already carries the model's state, thinking included, and each new token replaces the previous one. And stop on any reason other than `CONTINUATION`, then run the final reason through the table above.

Google's guide contradicts itself on one point: it shows the first non-streaming REST hop with `maxOutputTokens` 262,144, yet also says a non-streaming REST call above 32,768 without a token returns 400. On the gateway tested, a non-streaming request with 40,000 returned 200. If Google's API gives you that 400 on the first hop, use the SDK or `streamGenerateContent` instead. A streaming loop needs one more rule: after the first 32,768 tokens the stream sends a checkpoint token every 5,000 tokens, so hold new chunks as pending until a chunk with a token arrives, discard the pending ones if the stream drops, and resume from the last token.

To resume after `MAX_TOKENS`, send the same request with its token and a `maxOutputTokens` above the tokens already used; a value at or below that returns 400 "Continuation token has already used output tokens…".

## Gateway and OpenAI-compatible endpoints: results from October 28, 2026

On the gateway tested, Argon never returned a `continuationToken`, so no answer through it can be continued. A budget that ran out started over from scratch on the next request, and a reply cut at the cap on its OpenAI-compatible endpoint came back labeled `stop`. The gateway was LaoZhang API (`api.laozhang.ai`), which serves Argon on a Gemini-native `generateContent` path and an OpenAI-compatible `/v1/chat/completions` path. Requests went from a local HTTP proxy to the gateway, and the whole set cost at most $0.59 at Google's list price, counting the two dropped long runs as fully billed.

*Disclosure: [laozhang.ai is our own service](https://blog.laozhang.ai/en/about#laozhang). Its prices are platform pricing, not an independent comparison.*

| Request | What came back | What it means for your code |
| --- | --- | --- |
| Native, `maxOutputTokens` 64, `thinkingLevel` low | `MAX_TOKENS`, 291 characters, 64 output tokens, no `continuationToken` | Nothing to resume; resending the request produced a new answer from the start |
| Native, `maxOutputTokens` 200, `thinkingLevel` high, hard math prompt | `MAX_TOKENS`, 0 characters of text (197 thinking + 3 output tokens), HTTP 200 | An empty answer with no error; check the text, not the status code |
| Native non-streaming, `maxOutputTokens` 40,000, "Reply with exactly: OK" | `STOP`, "OK" | No 400 here, although Google documents one for direct REST above 32,768 |
| Native, `thinkingLevel` "minimal" | HTTP 500 with a generic "upstream service error" message in Chinese and code "402" | Argon rejects `minimal`; the gateway hid Google's actual error text |
| OpenAI-compatible, `max_tokens` 64, same long prompt | `completion_tokens` 64, `finish_reason` "stop" | A cut reply labeled `stop`; compare `completion_tokens` with `max_tokens` |
| Native non-streaming, `maxOutputTokens` 33,000, 2,500-row CSV | Connection closed at 300.9 seconds, no body | No reason, no usage, nothing to resume |
| `streamGenerateContent`, same CSV | 74,760 characters (up to row 1,065) over 993 events, then the stream ended at 302.5 seconds | See the next section |

Two rules follow for any gateway. First, on an OpenAI-style endpoint, don't trust `finish_reason` alone: if `completion_tokens` reached `max_tokens`, treat the reply as truncated and raise `max_tokens`, because that endpoint cannot continue. Second, check a gateway before relying on it for long answers. Google's guide says a `MAX_TOKENS` reply from its API still carries a token, so a cheap test is a single request with `maxOutputTokens` 64: if the reply ends in `MAX_TOKENS` without `continuationToken`, that gateway won't carry a long answer.

```python
def openai_truncated(resp, max_tokens):
    used = (resp.get("usage") or {}).get("completion_tokens", 0)
    return resp["choices"][0].get("finish_reason") == "length" or used >= max_tokens
```

The ~300-second cut on both long runs is shorter than Google's documented 10- and 20-minute server limits. It happened somewhere between the client and the gateway, a path that included the local HTTP proxy, and which of the two closed the connection was not determined. If a request sent through your own proxy or gateway keeps dying near five minutes, check the timeouts on every layer you control before blaming the model.

## Stream ended with no finishReason: incomplete, not done

A stream that ends without a finish reason did not finish, even if it returned plenty of text. In the October 28 test the last chunk carried `"finishReason": ""` (an empty string), the intermediate chunks reported `candidatesTokenCount` 0, and no final usage or checkpoint token ever arrived; the CSV stopped at row 1,065 of 2,500. Code that treats "stream closed without an exception" as success would have shipped less than half the file.

Treat a missing or empty reason as incomplete. If you saved a checkpoint token, send the original request again with it and drop the chunks received after that checkpoint. If the stream dropped before the first checkpoint, which only appears after 32,768 tokens, resend the original request. Google's guide says a stream dropped before 32K tokens costs nothing, and after that you pay up to the last checkpoint. The SDK does this resume for you, up to three reconnects without progress.

## Why prompt_token_count looks huge after long decode

After a multi-hop answer, `prompt_token_count` counts every hop's input, and each hop re-sends your prompt plus everything generated so far. Google's guide gives the arithmetic for a 1,000-token prompt that produces 200,000 tokens of thinking and output in four SDK hops: 1,000 + 66,536 + 132,072 + 197,608 = 397,216 input tokens reported, and about 597,000 total, while the real context is about 201,000 tokens. The same job over non-streaming REST takes seven 32K hops and reports 695,128 input tokens.

![Bar chart of input re-sent on four SDK hops, 1,000 to 197,608 tokens, adding up to 397,216 reported against about 201,000 tokens of real context](https://blog.laozhang.ai/posts/en/gemini-4-argon-api-finish-reason/img/long-decode-token-count.webp)

The SDK mock run showed the same pattern at small scale: a 120-token prompt reported `prompt_token_count` 33,008 after two hops (120 + 32,888), while `initial_prompt_token_count` stayed at 120. Read `initial_prompt_token_count` (Python) or `initialPromptTokenCount` (JavaScript) for prompt size and context trimming. The SDK computes it on the client, so it isn't in REST responses or in `model_dump()`; save it separately if you log responses. Over REST, add each usage field across hops for cost and keep the first hop's `promptTokenCount` as the prompt size, as the loop above does. A gateway that calls REST for you has to do the same, or its usage numbers won't match what the SDK reports for the same request.

For cost, you pay for every token in every hop, including hops that are pure thinking. Implicit caching discounts the repeated input in each hop by 95%, $0.10 instead of $2.00 per million tokens during the introductory pricing, but the cache expires after 15–20 minutes idle, so a long pause between hops brings back the full input rate. A failed non-streaming hop costs nothing. If the bills are higher than expected because Argon is the wrong model for the job, [Gemini 4 Argon vs 3.8 Flash: Cost per Task and When to Switch](https://blog.laozhang.ai/en/posts/gemini-4-argon-vs-gemini-3-8-flash) compares the same tasks on both.

## Sources

External pages this guide links to, in the order they appear. Last updated 2026-10-28.

- [long decode guide for generateContent](https://ai.google.dev/gemini-api/docs/generate-content/long-decode) (ai.google.dev)
- [Gemini API generateContent reference](https://ai.google.dev/api/generate-content) (ai.google.dev)
- [Gemini API pricing page](https://ai.google.dev/gemini-api/docs/pricing) (ai.google.dev)
- [Gemini API changelog](https://ai.google.dev/gemini-api/docs/changelog) (ai.google.dev)
- [available regions list](https://ai.google.dev/gemini-api/docs/available-regions) (ai.google.dev)
- [Interactions long decode guide](https://ai.google.dev/gemini-api/docs/long-decode) (ai.google.dev)
