Skip to content
Class 89 · Measurement · Free, no signup

The Model Got Smarter.
Your Ceiling Didn't.

Gemini 3.8 Flash costs exactly what 3.7 Flash costs and answers just as well — right up until a hard problem, where it spends up to 2.2× 3.7's worst-case thinking budget. Thinking tokens bill against maxOutputTokens. So the ceiling that fitted 3.7 truncates 3.8, and the truncation arrives as HTTP 200, finishReason: STOP, and an empty string.

252 API calls 3 models 1 of 6 tasks truncated 0 price difference 2 retractions ~50 min read

Quick answer

Gemini 3.8 Flash is not less capable than 3.7, and it is not more expensive per token — both cost $0.75 in and $3.75 out per million. What changed is the shape of its thinking spend. Across five hard tasks at an identical ceiling the medians nearly touch (3.7 at 1,197 tokens, 3.8 at 1,635), but the maxima do not: 3.7 never exceeded 2,679, while 3.8 reached 5,894. On one task in six that overrun consumed the entire 6,144-token allowance, and the API returned HTTP 200 with finishReason: STOP and zero bytes of text. Raising only maxOutputTokens to 16,384 turned the same task from 0 of 5 into 3 of 3. It is a budget limit, not a capability limit — and since thinking bills at the output rate, the same work now costs more at the same advertised price.

Key takeaways

  1. maxOutputTokens is a shared budget, not a cap on the answer. Google's own pricing column reads “output price (including thinking tokens)”. Reasoning spends the budget first.
  2. Size the ceiling against the maximum, not the median. 3.8's median is 1,635 and its max is 5,894. A ceiling chosen from the median is chosen from the wrong number.
  3. The failure is silent. HTTP 200, STOP, and an empty body. Checking response.ok catches nothing; checking finishReason catches nothing either.
  4. A test that returns the same answer for every input is not a test. Three of our batteries scored identically for all three models. That is one instrument failure, not three findings.
  5. Small samples hand you confident, wrong headlines. At n=8, 3.8 looked twice as slow. At n=20 the effect vanished.
  6. Confirm a failure by a second method before you report it. Ours changed meaning twice on the way to being understood.
MODULE 00

The model, and what its own card doesn't say

Gemini 3.8 Flash was published on 2 September 2026, model code gemini-3.8-flash, built on 3.7 Flash. It takes 1,048,576 input tokens and returns up to 65,536. Thinking is supported at low, medium and high. There is no audio or image generation, no Live API, and computer use is in Preview. Its self-reported knowledge cutoff is March 2026.

That is the specification. Two smaller things turned up while measuring it, and both are the kind of detail that only appears if you call the API rather than read about it.

The minimal thinking level did not change at 3.8

The documentation reads as though minimal was dropped for this release. It was not. Measured across all three models:

gemini-3.6-flash   thinkingLevel=minimal   ACCEPTED
gemini-3.7-flash   thinkingLevel=minimal   HTTP 400
                   "Thinking level MINIMAL is not supported for this model"
gemini-3.8-flash   thinkingLevel=minimal   HTTP 400  (identical message)

The change landed at 3.7. If you are still passing minimal anywhere, it has been failing since the previous release, not this one — and if your code treats a 400 as a transient error and retries, it has been paying for retries that cannot succeed.

The version string is inconsistent

Ask each model to identify its version and the older two answer in a stable format. The new one does not:

ModelReported versionNames itself?
gemini-3.6-flash3.6-flash-07-2026no — answers “Gemini”
gemini-3.7-flash3.7-flash-08-2026yes
gemini-3.8-flash3.0yes

Cosmetic on its own. It stops being cosmetic if anything in your stack routes, logs or gates on that string.

What the launch page publishes, and what it doesn't

Four benchmark claims appear on the model's page. One carries a number.

ClaimFigure givenBaseline given
HLE-Verified54.9%none
DeepSWE v1.1“outperforms most larger frontier models”none
Vals Finance Agent v2“outperforms 3.7 Flash”none
Harvey's Legal Agent Benchmark“outperforms”none

There is no comparison table on the page. That is not an accusation — marketing pages are marketing pages — but it does mean that if you want to know whether 3.8 is better for your workload, the published material cannot tell you. Which is the entire reason this class exists.

One thing the card says plainly, and it matters

Frontier Safety was not re-evaluated for 3.8. The card states that its conclusions are inferred from 3.7's results. Meanwhile the card's own safety deltas show text-to-text improving 0.4 points, image-to-text unchanged, tone worsening 0.2, unjustified refusals worsening 1.1, and multilingual regressing by 5.4 points. If you serve non-English users, that is the number on the page you should care about most, and it is the one nobody put in a headline.

MODULE 01

Three identical numbers are not three findings

The first battery ran seven phases against all three models. Here is what four of them returned.

Test3.63.73.8Information gained
Context / output limits1,048,576 / 65,536samesamenone
Structured output, n=1212/1212/1212/12none
Coding battery, easy, 10 tasks10/1010/1010/10none
Knowledge cutoff, self-reportedMarch 2026March 2026March 2026none

It is tempting to write that up as “3.8 matches 3.7 on structured output and coding”. That sentence is true and worthless. The tests could not have produced any other result. An instrument that returns the same reading for every input is not measuring the input — it is measuring itself, and reporting its own constant.

Four identical rows are not four findings. They are one failure of instrument design. The correct response is not to publish them as a result; it is to raise the difficulty until the instrument can distinguish, and to keep raising it until something separates.

Which of these is a measurement?

Work these before reading on. Each is a real result from this research, and the question is the same each time: could this test have told you the models differ, if they did?

Interactive · Decidercase 1 of 6

Measurement, or formality?

Six results from this class's own test runs. For each: was the test capable of showing a difference?

All three models report a 1,048,576-token context window.

caps.json — one call per model

Your answers stay in this browser. Nothing is sent anywhere. Reset clears them.

Why publish the dead tests at all

Because recognising a dead instrument is the transferable skill, and because leaving them out would make this research look tidier than it was. Roughly 96 of the 252 calls went to tests that could not have found anything. That is the real cost of not thinking about discrimination first, and it is worth showing rather than quietly deleting.

MODULE 02

n=8 said twice as slow. n=20 said no.

The latency phase ran first, because latency is easy to measure and everybody wants the number. At eight samples per model it produced a clean, quotable, wrong headline.

Median latency3.63.73.8Headline it supports
n = 8736.0 ms670.5 ms1,329.7 ms“3.8 is twice as slow”
n = 20868.1 ms603.7 ms680.0 msno effect worth reporting

Nothing changed between those two rows except the number of samples. The n=8 run was not corrupted, mistimed or unlucky in any way that could have been spotted at the time. It contained a 5,087 ms outlier — a ten-fold spread across eight calls — and with eight samples one outlier moves the median.

Retracted

“Gemini 3.8 Flash is roughly twice as slow as 3.7.” True of the n=8 run, false of the n=20 run, and it was never true of the model. Method that produced the error: too small a sample against a long-tailed distribution. Both runs are kept in the published results as latency_n8.json and latency.json, because the retraction is more useful than the number ever was.

This is the ordinary way benchmark claims go wrong. Not fraud, not incompetence — a sample too small to see past the tail, run by someone who stopped as soon as the result looked interesting. The defence is boring and reliable: decide the sample size before you look at the result, and for anything timing-related assume the distribution has a tail until you have seen enough of it to know otherwise.

Which number describes what a user experiences?

Interactive · Huntround 1 of 3

Find the number that survives scrutiny

Three rounds. In each, exactly one of the figures is the one you could defend to somebody who asks how you measured it.

Latency for 3.8 Flashwhich one goes in the report?
four figures, all arithmetically correct

Your answers stay in this browser. Nothing is sent anywhere. Reset clears them.

MODULE 03

Raise the threshold until it can fail

After the easy battery returned 10/10 three times, the choice was to publish “no measurable difference” or to build a test that could actually fail. The second battery kept the same shape — ten tasks, code returned in a fenced block, graded by executing it — and changed one thing: each task carries between four and eight adversarial vectors, and passes only if every vector passes.

The vectors are the cases people actually get wrong. Empty input. A pattern that requires backtracking. A quoted comma. A doubled quote inside a quoted field. Banker's rounding on a negative tie. A tie in a longest-palindrome search where the leftmost must win. A pre-release version suffix that sorts before the release it belongs to.

easy battery      3.6  10/10     3.7  10/10     3.8  10/10
hard battery      3.6  10/10     3.7  10/10     3.8   9/10   <-- h08_version_full

One task, on the newest model. Which is exactly the result most likely to be an artifact, so it was not reported until it had survived two more methods.

The first reading was not trustworthy

The harness recorded h08_version_full FAIL — missing 'def vcmp'. That is a string check on the extracted code, not an execution failure. It is equally consistent with the model naming the function differently, wrapping it in a class, or the fenced-block extraction missing. And it was n=1. A single grader-level mismatch is not a finding about a model; it is a note to go and look.

Second method: does it reproduce?

same prompt, same grader, n=5 per model

gemini-3.7-flash    5/5 PASS
gemini-3.8-flash    0/5 PASS

Reproducible, and not marginal. At that point the failure is real. What it means was still unknown, and the obvious interpretation — that 3.8 is worse at comparing version strings — turned out to be wrong.

Claim against measurement

Six statements. Each pairs something it would be reasonable to believe with what the runs actually recorded.

Interactive · Ledgerclaim 1 of 6

Six claims, six measurements

Each row states a claim and the figure measured against it. Decide whether the measurement supports the claim.

3.8 is slower than 3.7

Your answers stay in this browser. Nothing is sent anywhere. Reset clears them.

MODULE 04

Capability, or budget?

A model fails a task. There are two explanations, and they call for opposite responses:

  • Capability limit — it cannot do the work. Change models, change the prompt, or do it another way.
  • Budget limit — it can do the work but ran out of room. Change one number in your config.

They look identical from the outside. Both produce a missing answer. And there is exactly one way to tell them apart: raise the allowance and change nothing else. Same prompt, same grader, same vectors, same model. One variable.

CAPABILITY, OR BUDGET?identical prompt and grader; only maxOutputTokens differsmaxOutputTokens = 6,144ceiling3.62/23.73/33.80/2overmaxOutputTokens = 16,384ceiling3.6not run3.7not run3.83/33.8 is not less capable. It does not fit. The 16,384 bar is drawn at the observed maximum, 9,939 + output.
The ladder. Left: at 6,144 tokens, 3.8's thinking (5,898) plus the ~350 tokens the answer needs exceeds the ceiling, and the task fails 0 of 2. Right: at 16,384, the same task passes 3 of 3, with thinking measured at 6,154, 9,939 and 6,960. Nothing else was altered between the two panels.
at 6,1440 / 23.8 Flash
at 16,3843 / 33.8 Flash
at 6,1443 / 33.7 Flash
at 6,1442 / 23.6 Flash

It is a budget limit. 3.8 can compare version strings, including the pre-release ordering rule that makes the task awkward. It simply could not do it inside an allowance that 3.6 and 3.7 both fit comfortably.

The tail, not the centre

Having established that on one task, the obvious next question is whether it generalises. Five more hard tasks were run against all three models at the same 6,144 ceiling, recording thinking tokens on every call.

THINKING TOKENS PER TASKsame ceiling (6,144) for both; median of n=2-3; sorted by 3.802,0004,0006,0006,144h050.93xh101.17xh011.60xh091.22xh072.65xh082.03x3.7 Flash3.8 Flashmedian 3.7 1,197 · 3.8 1,635 | max 3.7 2,679 · 3.8 5,894The centres nearly touch. The worst cases do not. A ceiling sized on the median is sized on the wrong number.
Paired thinking spend, sorted by 3.8. On the easy end the pairs almost touch, and on h05 3.8 thinks less than 3.7. The separation appears only at the hard end — h07 at 2.65× and h08 at 2.03×.
Task3.63.73.83.8 / 3.7Outcome
h05_toposort_det1,2689759100.93×all pass
h10_lru_order1,3631,1151,3001.17×all pass
h01_glob2,0171,0531,6901.61×all pass
h09_wrap_hard3,1311,6301,9821.22×all pass
h07_strip_comments2,1851,9555,1792.65×all pass — barely
h08_version_full2,7022,9095,8982.03×3.8: 0 of 2
median, 5 tasks1,1973.7 — the efficient one
median, 5 tasks1,6353.8
max observed2,6793.7
max observed5,8943.8 — 2.2× 3.7

Read the medians alone and you would write “3.8 thinks a bit more than 3.7, less than 3.6”, which is true and useless. The distributions differ in their tails, not their centres. 3.7 never exceeded 2,679 thinking tokens on any task tested. 3.8 reached 5,894 — against a ceiling of 6,144.

h07 is the warning shot

h07_strip_comments passed. It spent 5,894 thinking tokens against a 6,144 ceiling250 tokens of headroom, roughly four percent. It passed on variance, not on margin. Run it on a day the model reasons slightly longer and it fails exactly as h08 did, and returns an empty string while doing it. One task in six truncated; a second came within a rounding error.

None of which means “3.8 truncates”. One task in six did, at n=2 to 3. That is a signal, not a rate. What it does mean is that the variable you never tuned — the ceiling you set once, against a different model, probably by copying an example — is now the thing most likely to break, and it will break on your hardest inputs rather than your typical ones.

MODULE 05

HTTP 200. STOP. Zero bytes.

Here is what the two failing calls actually returned. Both are successful HTTP requests. Neither raised an exception. One of them is detectable and one is not.

TWO RESPONSES YOUR CODE CANNOT TELL APARTboth are HTTP 200; only one contains a programGOODHTTP status200finishReasonSTOPcandidatesTokenCount425parts[0].text length1228code extractedyesSILENT FAILUREHTTP status200finishReasonSTOPcandidatesTokenCount7parts[0].text length0thoughtsTokenCount5,898finishReason is STOP in both. Checking response.ok, or trusting finishReason, catches neither.
Two responses, one difference that matters. finishReason is STOP in both the good response and the worst failure. The status code is 200 in both. Only the body distinguishes them.

The second failing call at least set finishReason: MAX_TOKENS and returned 242 bytes of a half-written function — ugly, but detectable, and a parser would have choked on it loudly. The first is the dangerous one:

HTTP status              200
finishReason             STOP
candidatesTokenCount     7
thoughtsTokenCount       5,898
parts[0].text            ""        <-- length 0

Every check most code performs passes. The request succeeded. The model reported that it stopped normally. There is a candidates array, a content object, a parts array. It is all there. It is just empty.

Anatomy of the response you actually get

Interactive · Anatomyregion

The response object, field by field

What each field tells you about a truncated call — and what it does not.

A generateContent response from the failing call

Your answers stay in this browser. Nothing is sent anywhere. Reset clears them.

What to actually check

The gauntlet below is the order the checks have to run in. Each gate lets some failures through; the point is which ones, and what is left standing at the end.

Interactive · Gate Runnercandidate 1 of 4

Run each response through the gauntlet

Five checks, in order. Four responses. See how far each gets before something catches it — and which check does the catching.

A good response: 425 output tokens, 1,228 bytes of text, code extracted

Your answers stay in this browser. Nothing is sent anywhere. Reset clears them.

Note what gate five is for. It never fails a response; it fails a configuration. If your hardest real prompt is consistently spending 5,894 of a 6,144-token allowance, you do not yet have a bug — you have four percent of headroom and a bug scheduled for whenever your inputs get slightly harder.

MODULE 06

Same price. More thinking.

The last piece is the one that turns a curiosity into a budget line. Read from the pricing page on 4 September 2026, Standard tier:

Per 1M tokens3.6 Flash3.7 Flash3.8 Flash
Input$0.75$0.75$0.75
Output — including thinking tokens$3.75$3.75$3.75
From 1 January 2027$1.50 / $7.50$1.50 / $7.50$1.50 / $7.50

Identical to the cent. And the phrase “output price (including thinking tokens)” is not our gloss — it is the column heading on the pricing page. Reasoning is billed as output.

Put the two facts together. Same list price, and on hard problems 3.8 spends up to 2.2× 3.7's worst-case thinking. On the tasks that matter most, the identical advertised rate buys you a larger bill for the same work — and, if your ceiling is unchanged, a chance of no work at all.

How we nearly published the wrong price, and how it was caught

The first two attempts to read these figures returned identical rows for all three models — which is what we ended up publishing, so they looked correct. They were not: the extraction had climbed the DOM to a shared ancestor and was reading one table three times. Indistinguishable from the true answer.

It was settled by the same principle as module 01: prove the instrument can return a different answer before believing the answer it returned. Scoped by document order and re-run, Flash-Lite came back at $0.30, 3.5 Flash at $1.50 and 3.1 Pro at $2.00. The scraper could discriminate. Only then was the sameness a finding. The bug in the scraper and the thesis of the class turned out to be the same bug.

Size your own ceiling

Fill in what you measured. The output is a guard you can paste into your own code: it sizes the ceiling from your observed worst case, and it fails loudly on the response that otherwise arrives as a successful, empty call.

Interactive · Forgelive

Build your ceiling guard

Four inputs. The generated file sizes maxOutputTokens from a measured maximum rather than a guess, and rejects the silent failure.


Your answers stay in this browser. Nothing is sent anywhere. Reset clears them.

What we would change tomorrow

  1. Re-run the hardest real prompts at the current ceiling before switching models. Not the test suite — the actual worst inputs, the ones that already make the model work. Those are the only ones that can show this.
  2. Log thoughtsTokenCount in production. It is free, it is on every response, and it is the only field that tells you how close you are running to the edge. Alert on the ratio, not on failures.
  3. Assert a non-empty body. One line. It converts an invisible failure into a visible one.
  4. Size ceilings from observed maxima with a multiplier, and write down the date and the sample size beside the number, so the next person knows whether to trust it.

Bottom line

Gemini 3.8 Flash is a good model at an unchanged price, and the interesting thing about it is not on its launch page. Its thinking spend has a heavier tail than 3.7's, thinking is billed and counted as output, and so the one number you set once and never revisited is now the one most likely to break — on your hardest inputs, silently, as a successful call that returns nothing.

The wider lesson cost more than the finding did. Three of our test phases returned identical results for all three models and could never have done otherwise. A latency headline held up at eight samples and died at twenty. A price carried forward from an earlier class overstated every cost here by a factor of two. Each of those was a confident, wrong answer produced by an instrument nobody had checked could fail. Prove the test can fail before you believe that it passed.

Confidence

Measured
Every figure in modules 01 to 06, from 252 generateContent calls made on 2026-09-04, with n stated beside each. Raw JSON retained for every call, including failures. Pricing and benchmark figures read from the rendered vendor pages the same day.
Calculated
All 3.8/3.7 ratios; all dollar amounts, derived from recorded token counts at the published rate.
Not verified
How general the truncation is — one task in six, at n=2 to 3. That is a signal, not a rate, and this page never says “3.8 truncates”. Whether the empty-body STOP is deterministic; it was seen once across two failures. DeepSWE was not run — the coding batteries here are a local proxy graded by executing returned code, and must not be read as a DeepSWE result. No DeepSWE figure is published for 3.8 by anyone, including Google.
Retracted, in public
“3.8 is twice as slow as 3.7” — true at n=8, false at n=20. And every cost figure in the working notes, computed at $7.50 per million output when the current rate is $3.75, because the number was carried forward instead of re-read.

Questions

What actually changed between Gemini 3.7 Flash and 3.8 Flash?

Measured across 252 API calls on 4 September 2026: nothing changed in price, context limits or correctness, and one thing changed in behaviour. Both models cost 0.75 dollars per million input tokens and 3.75 dollars per million output tokens. Both accept 1,048,576 input and 65,536 output tokens. On every correctness test where both had room to answer, both scored identically. What changed is how much of the output allowance the model spends thinking on a hard problem. On the two hardest tasks tested, 3.8 spent 2.03 and 2.65 times what 3.7 spent, and on one of them it exhausted the allowance and returned nothing.

Why does a thinking budget matter if I never set one?

Because you did set one, whether or not you meant to. Thinking tokens are billed and counted as output tokens — that is the Gemini pricing page's own column heading, which reads output price including thinking tokens. So maxOutputTokens is not a limit on the answer, it is a shared budget that the model's reasoning spends first and your answer spends second. If reasoning consumes the budget, there is nothing left for the answer, and the request completes anyway.

What does the failure actually look like in code?

In the worst observed case: HTTP status 200, finishReason STOP, candidatesTokenCount 7, and parts[0].text of length zero. Not an error, not an exception, not a MAX_TOKENS flag. A second failure on the same task did return finishReason MAX_TOKENS with a function truncated mid-body, which at least is detectable. The dangerous one is the first, because every obvious check passes: the request succeeded, the model stopped normally, and the response is empty.

Is 3.8 Flash worse at coding than 3.7?

No, and the page is careful about this. On ten adversarial coding tasks at a 6,144-token ceiling, 3.6 scored 10 of 10, 3.7 scored 10 of 10 and 3.8 scored 9 of 10. The single failure was not a wrong answer — it was a truncation. Raising only maxOutputTokens to 16,384, changing nothing else about the prompt or the grader, turned that task from 0 of 5 into 3 of 3. It is a budget limit, not a capability limit, and those two are only told apart by raising the allowance and observing what happens.

Does 3.8 Flash think more than 3.7 in general?

No, and claiming so would be false. Across five hard tasks at an identical ceiling, the median thinking spend was 1,197 tokens for 3.7, 1,635 for 3.8 and 1,799 for 3.6 — so 3.7 is the efficient one and 3.8 sits between the other two. On one task 3.8 thought less than 3.7. What moved is the tail, not the centre: 3.7 never exceeded 2,679 thinking tokens on any task tested, while 3.8 reached 5,894, which is 2.2 times 3.7's worst case. Sizing a ceiling on the median is sizing it on the wrong number.

Which tests in this research measured nothing, and why publish them?

Three. Context and output limits returned identical values for all three models. Structured output returned 12 of 12 for all three. An easy ten-task coding battery returned 10 of 10 for all three. A metric that gives the same answer for every input cannot see a difference, so those are not three findings, they are one failure of instrument design. They are published because recognising a dead instrument is the transferable skill, and because leaving them out would make the research look tidier than it was.

What was retracted from this research?

A latency headline. At a sample of 8, 3.8's median response time was 1,329.7 milliseconds against 3.7's 670.5 — a clean claim that 3.8 is twice as slow. At a sample of 20 the same measurement gave 680.0 against 603.7, and the claim evaporated. The distribution has a long tail, and eight samples were not enough to see past it. Both runs are kept in the published results. A second retraction concerns cost: every dollar figure in the research notes was originally computed at 7.50 dollars per million output tokens, a rate carried forward from an earlier class instead of re-read, when the current rate is 3.75. Every cost was overstated twofold until it was corrected.

Does the model card get anything wrong?

Two things worth knowing. The documentation reads as though the minimal thinking level was removed at 3.8; measured, it is rejected with HTTP 400 by both 3.7 and 3.8 and accepted by 3.6, so the change landed at 3.7. And the API's own reported version string is 3.6-flash-07-2026 and 3.7-flash-08-2026 for the older models, but simply 3.0 for 3.8 — cosmetic, unless something in your stack parses that field. Separately, the card states that Frontier Safety was not re-evaluated for 3.8 and is inferred from 3.7's results, and its multilingual safety figure regressed by 5.4 percentage points.

What benchmark numbers did Google publish for 3.8 Flash?

One. The launch page states 54.9 percent on HLE-Verified, with no 3.7 baseline to compare it against. DeepSWE v1.1, Vals Finance Agent v2 and Harvey's Legal Agent Benchmark are each claimed as outperforming, with no figure attached to any of them, and there is no comparison table on the page. Four benchmark claims, one number, zero baselines. This class quotes the one number and names the other three as unquantified, because a claim without a figure cannot be checked and should not be repeated as though it could.

What should I actually change in my code after reading this?

Three things, none of them large. First, stop treating maxOutputTokens as a cap on the answer and size it as a shared budget, with headroom for reasoning that varies by task difficulty. Second, validate the response body rather than the response status: assert that text is non-empty and that whatever you expected to parse out of it is actually present, and treat a zero-length body as a failure regardless of finishReason. Third, when you change models, re-run your hardest cases at your existing ceiling before you ship, because the tasks that break are the ones your easy tests cannot see.