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
maxOutputTokensis 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.- 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.
- The failure is silent. HTTP 200,
STOP, and an empty body. Checkingresponse.okcatches nothing; checkingfinishReasoncatches nothing either. - 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.
- Small samples hand you confident, wrong headlines. At n=8, 3.8 looked twice as slow. At n=20 the effect vanished.
- Confirm a failure by a second method before you report it. Ours changed meaning twice on the way to being understood.
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:
| Model | Reported version | Names itself? |
|---|---|---|
| gemini-3.6-flash | 3.6-flash-07-2026 | no — answers “Gemini” |
| gemini-3.7-flash | 3.7-flash-08-2026 | yes |
| gemini-3.8-flash | 3.0 | yes |
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.
| Claim | Figure given | Baseline given |
|---|---|---|
| HLE-Verified | 54.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.
Three identical numbers are not three findings
The first battery ran seven phases against all three models. Here is what four of them returned.
| Test | 3.6 | 3.7 | 3.8 | Information gained |
|---|---|---|---|---|
| Context / output limits | 1,048,576 / 65,536 | same | same | none |
| Structured output, n=12 | 12/12 | 12/12 | 12/12 | none |
| Coding battery, easy, 10 tasks | 10/10 | 10/10 | 10/10 | none |
| Knowledge cutoff, self-reported | March 2026 | March 2026 | March 2026 | none |
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?
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
All three models scored 12/12 on structured output.
schema.json — n=12 per model
All three models scored 10/10 on the easy coding battery.
coding.json — 10 tasks per model
3.8's median thinking spend was 1,635 tokens against 3.7's 1,197.
thinking_gap.json — 5 tasks x n=2
thinkingLevel=minimal returns HTTP 400 on 3.7 and 3.8, and succeeds on 3.6.
thinking.json — 4 levels x 3 models
3.8 failed h08_version_full at a 6,144-token ceiling; 3.6 and 3.7 passed.
coding_hard.json, then confirmed at n=5
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.
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 latency | 3.6 | 3.7 | 3.8 | Headline it supports |
|---|---|---|---|---|
| n = 8 | 736.0 ms | 670.5 ms | 1,329.7 ms | “3.8 is twice as slow” |
| n = 20 | 868.1 ms | 603.7 ms | 680.0 ms | no 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?
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.
four figures, all arithmetically correct
Three describe the sample. One describes the model.
the ceiling has to cover something
A limit is not sized by typical behaviour.
the token counts are recorded
Rates carry expiry dates.
Your answers stay in this browser. Nothing is sent anywhere. Reset clears them.
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.
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
measured delta +76.3 ms +12.6%
3.8 thinks more than 3.7 in general
measured delta +438 tokens +36.6%
The models differ in worst-case thinking spend
measured delta +3215 tokens +120.0%
3.8 costs more per token than 3.7
measured delta 0.0 USD 0.0%
3.8 cannot do the version-comparison task
measured delta +10240 tokens +166.7%
A failed call is obvious from the response
measured delta -242 bytes -100.0%
Your answers stay in this browser. Nothing is sent anywhere. Reset clears them.
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.
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.
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×.
| Task | 3.6 | 3.7 | 3.8 | 3.8 / 3.7 | Outcome |
|---|---|---|---|---|---|
| h05_toposort_det | 1,268 | 975 | 910 | 0.93× | all pass |
| h10_lru_order | 1,363 | 1,115 | 1,300 | 1.17× | all pass |
| h01_glob | 2,017 | 1,053 | 1,690 | 1.61× | all pass |
| h09_wrap_hard | 3,131 | 1,630 | 1,982 | 1.22× | all pass |
| h07_strip_comments | 2,185 | 1,955 | 5,179 | 2.65× | all pass — barely |
| h08_version_full | 2,702 | 2,909 | 5,898 | 2.03× | 3.8: 0 of 2 |
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 ceiling — 250 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.
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.
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
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 callYour 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.
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
- response.ok / HTTP 2xxCatches network and API errors. Catches no truncation of any kind.pass
- finishReason is not MAX_TOKENSCatches the loud truncation. Misses the zero-byte one, which reports STOP.pass
- parts[0].text has non-zero lengthCatches the empty body. This is the check almost nobody writes.pass
- the structure you expected parses out of the textCatches a body that is present, non-empty, and still not what you asked for — a preamble with no fenced code, or JSON that stops mid-object.pass
- thoughtsTokenCount is below your ceiling with marginNot a correctness check — an early warning. It tells you a call nearly ran out of room before one actually does.pass
The loud failure: finishReason MAX_TOKENS, 242 bytes, function cut mid-body
- response.ok / HTTP 2xxCatches network and API errors. Catches no truncation of any kind.pass
- finishReason is not MAX_TOKENSCatches the loud truncation. Misses the zero-byte one, which reports STOP.REFUSED
- parts[0].text has non-zero lengthCatches the empty body. This is the check almost nobody writes.never reached
- the structure you expected parses out of the textCatches a body that is present, non-empty, and still not what you asked for — a preamble with no fenced code, or JSON that stops mid-object.never reached
- thoughtsTokenCount is below your ceiling with marginNot a correctness check — an early warning. It tells you a call nearly ran out of room before one actually does.never reached
The silent failure: HTTP 200, finishReason STOP, 7 output tokens, empty text
- response.ok / HTTP 2xxCatches network and API errors. Catches no truncation of any kind.pass
- finishReason is not MAX_TOKENSCatches the loud truncation. Misses the zero-byte one, which reports STOP.pass
- parts[0].text has non-zero lengthCatches the empty body. This is the check almost nobody writes.REFUSED
- the structure you expected parses out of the textCatches a body that is present, non-empty, and still not what you asked for — a preamble with no fenced code, or JSON that stops mid-object.never reached
- thoughtsTokenCount is below your ceiling with marginNot a correctness check — an early warning. It tells you a call nearly ran out of room before one actually does.never reached
A response that returns prose apologising instead of code
- response.ok / HTTP 2xxCatches network and API errors. Catches no truncation of any kind.pass
- finishReason is not MAX_TOKENSCatches the loud truncation. Misses the zero-byte one, which reports STOP.pass
- parts[0].text has non-zero lengthCatches the empty body. This is the check almost nobody writes.pass
- the structure you expected parses out of the textCatches a body that is present, non-empty, and still not what you asked for — a preamble with no fenced code, or JSON that stops mid-object.REFUSED
- thoughtsTokenCount is below your ceiling with marginNot a correctness check — an early warning. It tells you a call nearly ran out of room before one actually does.never reached
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.
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 tokens | 3.6 Flash | 3.7 Flash | 3.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.
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
- 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.
- Log
thoughtsTokenCountin 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. - Assert a non-empty body. One line. It converts an invisible failure into a visible one.
- 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
generateContentcalls made on 2026-09-04, withnstated 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
STOPis 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.