# Nano Banana 2 API 报错：429、503、NO_IMAGE 怎么处理

> gemini-3.1-flash-image 报错处理：429 分清速率、每日配额与消费限速，503 有上限地退避，400、402、403 不要重试，NO_IMAGE 要改输入；中国大陆和港澳不在支持地区。

- Source: https://www.aifreeapi.com/zh/posts/nano-banana2-api-error-codes
- Language: zh
- Published: 2026-08-05
- Updated: 2026-09-25
- Publisher: AI Free API (https://www.aifreeapi.com)

Nano Banana 2 在 Gemini API 里的模型 ID 是 `gemini-3.1-flash-image`。报错时先别急着重试：只有 `429` 里的速率类错误、`408` 和 `5xx` 值得有上限地退避重试；`400`、`401`、`402`、`403`、`404` 要改请求、密钥或账单；每日配额用完要等重置；`IMAGE_SAFETY` 这类内容拦截要改提示词或参考图；地区不支持则重试多少次都一样。

还要先确认两件事：代码里的模型名是不是已经下线的 `gemini-3.1-flash-image-preview`，以及你用的是 Interactions API 还是 generateContent。两种接口报错的写法不同，前者是小写的 `no_image`、`quota_exceeded`，后者是大写的 `NO_IMAGE`、`RESOURCE_EXHAUSTED`。

## Nano Banana 2 报错对照表：按日志里的信号查处理

下表按“你在日志里看到什么”排列。错误代码列同时写了 Interactions API 的小写代码和 generateContent 常见的大写写法。

| 你看到的 | 问题在哪 | 先做什么 | 要不要重试 |
|---|---|---|---|
| `404`，`model_not_found`，模型名带 `-preview` | 模型 ID | 改成 `gemini-3.1-flash-image`，预览 ID 已于 2026 年 6 月 25 日停用 | 不要 |
| `400`，`invalid_request`、`parameter_unknown` 或 `INVALID_ARGUMENT` | 请求写法 | 按 message 改参数，常见的是 `image_size` 写成小写 `1k` | 不要 |
| `400`，`FAILED_PRECONDITION`，message 是 "User location is not supported for the API use" | 地区 | 发起调用的所在地不在支持列表，见下文地区一节 | 不要 |
| `400`，`failed_precondition`，message 与计费有关 | 账单前提 | 检查项目是否关联了可用的结算账号 | 不要 |
| `401`，`authentication` | 密钥 | key 缺失、写错或已过期 | 不要 |
| `403`，`permission_denied`，或 "Your API key was reported as leaked" | 权限 / 泄露 | 查 key 的项目权限；被判定泄露的 key 只能换新 | 不要 |
| `402`，`payment_required` | 预付费余额 | 余额用完，充值或开启自动充值 | 不要 |
| `429`，`rate_limit_exceeded` 或 `too_many_requests` | 每分钟 / 每秒上限 | 指数退避加随机抖动，降低并发 | 可以，有上限 |
| `429`，`quota_exceeded` | 每日配额 | 等太平洋时间午夜重置，或申请提额 | 当天不要 |
| `429 RESOURCE_EXHAUSTED`，10 分钟内调用了大量高价请求 | 按消费金额的限速 | 放慢 4K 等高价请求的节奏 | 稍等再试 |
| `500`，`api_error` | Google 服务端 | 退避重试，持续出现再联系支持 | 可以，有上限 |
| `503`，`UNAVAILABLE`，"This model is currently experiencing high demand" | 模型容量 | 退避重试，持续时降低并发 | 可以，有上限 |
| `504`，`deadline_exceeded` | 截止时间 | 去掉或放宽客户端 deadline | 调整后再试 |
| `499`，`cancelled` | 你的客户端 | 客户端在完成前断开了 | 查明原因再发 |
| HTTP 200，`finishReason: NO_IMAGE` 或 `no_image` | 生成结果 | 读返回的文字和 `finishMessage`，用最小请求对比 | 改输入后再试 |
| HTTP 200，`IMAGE_SAFETY`、`IMAGE_PROHIBITED_CONTENT` 或 `image_safety` | 内容政策 | 改提示词或参考图 | 原样重试无效 |
| 没有 `candidates`，只有 `promptFeedback.blockReason` | 提示被拦截 | 按 blockReason 改输入；`OTHER` 可能违反条款或属于不支持的用法 | 原样重试无效 |
| `finishReason: PUP_LIMITED_DISABLED` | 账户受限 | 账户因违反使用政策被限制，改提示词没用 | 不要 |

错误代码和 HTTP 状态的对应关系来自 Google 的 [API 错误参考](https://ai.google.dev/gemini-api/docs/api-errors)（截至 2026 年 9 月 20 日更新）；重试范围来自[故障排查文档](https://ai.google.dev/gemini-api/docs/troubleshooting)，其中明确写着只重试 `429`、`408` 和 `5xx`，不要重试 `400`、`402`、`403`。

## 先确认模型 ID 和调用方式

### 预览 ID 已经下线

Nano Banana 2 在 2026 年 2 月 26 日以 `gemini-3.1-flash-image-preview` 发布，5 月 28 日推出正式版 `gemini-3.1-flash-image`，预览 ID 同日被宣布弃用，并在 2026 年 6 月 25 日停止服务（见 [Gemini API 更新日志](https://ai.google.dev/gemini-api/docs/changelog)）。6 月之前写的示例代码如果还用预览 ID，照抄就会请求一个已经停用的模型。错误参考把这种情况归为 `model_not_found`，HTTP `404`，建议核对模型名。下线后具体返回什么 message，公开文档没有给出样例，所以只要看到 `404` 就先查模型字符串。

同系列的其他 ID 也值得核对一遍：Nano Banana 2 Lite 是 `gemini-3.1-flash-lite-image`，Nano Banana Pro 是 `gemini-3-pro-image`，最早的 Nano Banana 是 `gemini-2.5-flash-image`。2026 年 9 月 18 日起，Google 把“2.5 系列模型”限制为只对以前用过的用户开放，新项目改用新模型。更新日志没有写明这是否包括 `gemini-2.5-flash-image`，也没写被拒时返回什么代码；新项目如果在旧图片模型上碰到拒绝，直接换到 3.1 系列更省事。

### 两种接口，错误出现在不同位置

Google 的[图片生成文档](https://ai.google.dev/gemini-api/docs/image-generation)现在只展示 Interactions API（`POST /v1beta/interactions`）。按 [Interactions API 说明](https://ai.google.dev/gemini-api/docs/interactions)，它自 2026 年 6 月起正式可用，推荐新项目使用；原来的 generateContent 被称为旧版接口，但“仍然完全支持”，并没有弃用。两种接口都能调用 Nano Banana 2，出错时的样子却不一样：

| | Interactions API | generateContent |
|---|---|---|
| 请求级错误 | HTTP 状态码加 `{"error": {"code": "quota_exceeded", "message": "..."}}`，`code` 是小写下划线 | HTTP 状态码加错误体，状态名是大写，例如 `RESOURCE_EXHAUSTED`、`UNAVAILABLE` |
| 没出图 | 错误参考列出 `no_image`、`image_safety` 等代码；interaction 对象还有 `status`（`completed`、`failed`、`incomplete` 等）和 `errors` 字段 | 通常是 HTTP 200，原因在 `candidates[].finishReason` 或 `promptFeedback.blockReason` |
| 图片在哪 | `steps[].content[]` 里 `type` 为 `image` 的块，SDK 提供 `interaction.output_image` | `candidates[].content.parts[]` 里的 `inlineData` |

Interactions API 的流式请求（`stream: true`）出错时，会在 SSE 流里发出 `event_type` 为 `error` 的事件，结构同样是 `code` 加 `message`。

两点容易漏看。第一，HTTP 非 2xx 时也要读响应体：同样是 `400`，message 可能是参数错误，也可能是地区不支持；同样是 `429`，`code` 决定该退避还是等明天。第二，Interactions API 的错误参考只把 `no_image`、`image_safety` 列为错误代码，没有写清它们是随 HTTP 错误返回，还是出现在 `status` 为 `failed` 的 interaction 的 `errors` 里，所以解析时两处都要看。

![分层示意图：顶部 HTTP 请求层列出 400、429、503；中间 GenerateContent 生成结果层由 finishReason 分出 image part、NO_IMAGE 与 IMAGE_SAFETY；底部调用方或网关 deadline 层标出 timeout 后没有 response body、结果可能未知](https://www.aifreeapi.com/posts/zh/nano-banana2-api-error-codes/img/response-layers.webp)

上图按 generateContent 画出了三层信号：HTTP 状态、生成结束原因、调用方自己的超时。Interactions API 的请求级错误同样属于第一层，`no_image`、`image_safety` 属于第二层，只是字段位置不同。

### 用最小请求确认链路

排查时先用一个最简单的请求确认密钥、项目、模型和地区都没问题，再把复杂输入一项项加回去。下面是 Interactions API 的写法，把 HTTP 状态码和响应体分开保存：

```bash
curl -s -o nb2-probe.json -w "HTTP %{http_code}\n" \
  -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
  -H "x-goog-api-key: ${GEMINI_API_KEY:?先设置 GEMINI_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemini-3.1-flash-image",
    "input": "生成一张白色背景上的蓝色陶瓷杯产品图",
    "response_format": {"type": "image", "image_size": "1K"}
  }'
```

还在用 generateContent 的项目，对应的最小请求是：

```bash
curl -s -o nb2-probe.json -w "HTTP %{http_code}\n" \
  -X POST "https://generativelanguage.googleapis.com/v1beta/models/gemini-3.1-flash-image:generateContent" \
  -H "x-goog-api-key: ${GEMINI_API_KEY:?先设置 GEMINI_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "contents": [{"parts": [{"text": "生成一张白色背景上的蓝色陶瓷杯产品图"}]}],
    "generationConfig": {"responseModalities": ["IMAGE"]}
  }'
```

最小请求成功而原请求失败，问题就在输入、参数或并发上；最小请求也失败，再看密钥、账单、地区和服务状态。Nano Banana 2 是付费模型，成功出图就按输出计费，1K 标准价约 $0.067 一张（[Gemini API 价格页](https://ai.google.dev/gemini-api/docs/pricing)），探测请求不要放进循环里批量跑。

## 400、401、403、404：先改请求或密钥

这一组错误的共同点是：原样再发一次，结果不会变。

`400 invalid_request` 或 `parameter_unknown` 表示请求体格式或参数有问题。Nano Banana 2 上常见的几种：

- `image_size` 必须用大写 `K`（`512px` 对应的 0.5K、`1K`、`2K`、`4K`），文档明确写着小写的 `1k` 会被拒绝。0.5K 只有 Nano Banana 2 支持，Nano Banana 2 Lite 只支持 1K。
- 参考图最多 14 张，其中物体图最多 10 张、人物图最多 4 张。
- 模型卡片列出 Nano Banana 2 不支持函数调用、结构化输出、缓存、代码执行、URL 上下文、Live API，也不支持 Flex 和 Priority 两种推理档位；在请求里带上这些选项属于请求端错误。每种情况具体返回哪个代码，文档没有逐一列出。
- 路径里的 API 版本要对。故障排查文档提醒，Beta 功能只在 `/v1beta` 下可用。

还有一种不报错的情况值得注意：参数被忽略时，请求照样返回 200。GitHub 上有人报告，通过 Vertex AI 调用正式版 `gemini-3.1-flash-image` 时，无论 `imageSize` 设成 1K、2K 还是 4K，拿到的都是约 1K 的图（[js-genai #1682](https://github.com/googleapis/js-genai/issues/1682)，单个报告，状态不明）。对尺寸有要求的流程，应该在保存前检查输出图片的实际像素。

`401 authentication` 是 key 缺失、无效或过期。`403 permission_denied` 是这个 key 对资源没有权限，先查它属于哪个项目、项目是否启用了 Gemini API。Google 还会主动封禁已知公开泄露的 key，这时会看到 "Your API key was reported as leaked. Please use another API key."。被封的 key 不会恢复，只能在 AI Studio 新建一个，并检查 key 的保管方式；如果因泄露产生了意外费用，按故障排查文档的建议提交账单支持工单。

`404 model_not_found` 回到上一节：先查模型名。

## 地区限制：中国大陆、香港、澳门不在支持列表

Google 公布的 [Gemini API 与 AI Studio 可用地区](https://ai.google.dev/gemini-api/docs/available-regions)（2026 年 4 月 28 日更新）包括台湾、日本、新加坡、美国等，但没有中国大陆、香港和澳门。所以“Gemini API 国内可以用吗”的答案是：官方不支持。

在不支持的地区调用时，开发者报告收到的是 `400`、状态 `FAILED_PRECONDITION`、message 为 "User location is not supported for the API use" 的错误（这段文字来自用户报告，官方文档里没有这个样例；更早的报告里也有显示为 `403` 的）。要注意，官方对 `failed_precondition` 的定义是“前提条件未满足，例如未开启计费”，所以同一个 `400 FAILED_PRECONDITION` 既可能是地区问题，也可能是账单问题，要看 message 判断。

可用地区页面对 Colab 用户说得很明确：限制按 Colab 实例所在的地区判断，而不是按用户本人所在的地区。其他调用方式官方没有单独说明；如果本地测试正常、部署到另一台服务器后才报地区错误，先查那台服务器所在的地区。

这个错误等待和重试都不会消失。Google 在地区页面上建议不在列表里的用户改用 Gemini Enterprise Agent Platform 里的 Gemini API，但该平台能否面向中国大陆客户提供服务，公开页面没有说明，不能直接当作国内方案。各项 Gemini 服务的地区与年龄要求可以在[Gemini 目前不支持你所在的地区：先确认是哪项服务不可用](/zh/posts/gemini-not-available-in-your-region)里逐项核对。

## 三种 429：速率、每日配额和消费限速

`429` 在 Nano Banana 2 上至少有三种来源，处理方式不同：

| 类型 | 怎么认出来 | 怎么处理 |
|---|---|---|
| 每分钟 / 每秒上限（RPM、TPM、图片模型的 IPM） | Interactions API 返回 `rate_limit_exceeded` 或 `too_many_requests` | 指数退避加随机抖动，降低并发，把突发流量摊平 |
| 每日配额（RPD） | Interactions API 返回 `quota_exceeded` | 等太平洋时间午夜重置，或申请提额；当天重试只会继续失败 |
| 按消费金额的限速 | `429 RESOURCE_EXHAUSTED`，通常出现在短时间内大量生成高分辨率图片时 | 稍等后再试，降低高价请求的频率，经常碰到可以申请提高限额 |

generateContent 的 `429` 都显示为 `RESOURCE_EXHAUSTED`，光看状态名分不出是哪一种，要读 message，再到 AI Studio 对照当前用量。

几条会改变判断的规则都来自 [Gemini API 速率限制文档](https://ai.google.dev/gemini-api/docs/rate-limits)：

- **限额按项目计算，不按 API key 计算。** 同一个项目里换一个 key 不会让 429 消失。
- 每日请求数在太平洋时间午夜重置。
- 各层级的实际限额只在 AI Studio 里显示，官方也说明这些数字“不保证”。速率限制文档没有给出 Nano Banana 2 各层级的固定 RPM 或 IPM，网上流传的具体数字无法从官方页面核对。
- Nano Banana 2 在价格页上的免费层标注为“不可用”，没有绑定结算账号的项目用不了它。这种情况下具体返回什么错误，官方没有写明。想先免费试用，可以看[Nano Banana 免费使用：官方入口、额度与地区限制](/zh/posts/nano-banana-free-use)里整理的官方入口。

### 按消费金额的限速有多容易碰到

除了请求数，Google 还按滚动 10 分钟窗口内的消费金额限速：Tier 1 为 $10，Tier 2 为 $50，Tier 3 为 $200，超出就返回 `429 RESOURCE_EXHAUSTED`。这项限速是否适用取决于账户的计费历史和层级。

用 Nano Banana 2 标准价粗算 Tier 1 在 10 分钟里最多能出多少张图（只算输出费用）：

| 分辨率 | 每张输出价格 | $10 ÷ 单价 |
|---|---|---|
| 4K | $0.151 | 约 66 张 |
| 2K | $0.101 | 约 99 张 |
| 1K | $0.067 | 约 149 张 |
| 0.5K | $0.045 | 约 222 张 |

Tier 2 是这些数字的 5 倍，Tier 3 是 20 倍。实际能跑的量会更少：输入 token、思考 token、使用 Google 搜索建立依据的费用、以及失败重试都会占用同一笔金额，RPM 或 IPM 也可能先到上限。这张表只说明一件事：Tier 1 项目 10 分钟内集中跑几十张 4K 图，即使每分钟请求数不多，也可能收到 `429`。

429 与 AI Studio 网页端额度提示的区别，见[AI Studio 提示达到速率限制怎么办：先分清哪份额度](/zh/posts/gemini-api-rate-limit-explained)；层级资格、项目与结算账号的关系和查看当前限额的位置，见[Gemini API 分层速率限制：查清当前限额与 429 原因](/zh/posts/gemini-api-rate-limits-per-tier)。

## 402 和月度上限：账单停用不会自己恢复

按 [Gemini API 计费文档](https://ai.google.dev/gemini-api/docs/billing)，新用户默认使用预付费（Prepay）方式。预付费余额降到 $0 时，这个结算账号下所有项目的所有 API key 会同时停用，请求返回 `402 Payment Required`，直到充值为止。计费数据大约有 10 分钟延迟，批量任务可能在停用前继续消费，余额会显示为负数，这时服务同样暂停，负数部分从下次充值里扣除。开启自动充值可以避免中断。

余额明明大于 0 却停了，官方给出的解释是可能碰到了当前层级的月度消费上限。上限按结算账号计算，汇总所有关联项目：Tier 1 为 $250，Tier 2 为 $2,000，Tier 3 为 $20,000 到 $100,000。到达上限后，所有关联项目暂停到下个月 1 日，可以申请提高上限。以 Tier 1 的 $250 粗算，只算输出费用，大约是 1,655 张 4K 或 3,731 张 1K 图。这种暂停具体返回哪个错误代码，文档没有写明，所以看到不熟悉的拒绝时，先去 AI Studio 的消费页面看看是否到了上限。AI Studio 也可以给单个项目设置月度消费上限（实验功能），同一结算账号下有多个项目时可以用它分配额度。

`402` 和月度上限都属于“不要重试”的一类：重试不会让余额变多，只会让日志更难读。

## 500、503、504 与超时：有上限地退避

`500 api_error` 是 Google 服务端的意外错误，官方建议重试，持续出现就联系支持。`503 UNAVAILABLE` 表示服务暂时过载或不可用，用户看到的 message 常是 "This model is currently experiencing high demand"。这两种错误都不是你的请求写错了，Google 也没有公布恢复时间，正确做法是指数退避：第一次等 1 秒左右，之后 2 秒、4 秒、8 秒，加上随机抖动，并设定最大次数。

`504 deadline_exceeded` 是请求没能在截止时间内完成。官方建议去掉客户端 deadline 设置或把它调大，让服务端使用默认值。`499 cancelled` 则是你的客户端在完成前断开了连接，官方说明这种情况“无需处理”，但你要弄清是谁先断开的：浏览器、应用服务器，还是中间的反向代理。

Nano Banana 2 的调用时间和输入量、分辨率、思考级别都有关。Gemini 3.x 模型默认开启思考，Nano Banana 2 的 `thinking_level` 可设为 `minimal`（默认）或 `high`，`high` 更慢，思考 token 也要计费。4K 输出、`high` 思考和多张参考图叠在一起时，过短的客户端超时会把本来能完成的请求截断。这时服务端是否已经完成生成、是否计费，Google 没有说明；批量任务重发前，先在 AI Studio 里看一眼用量，避免重复生成。思考级别对耗时和费用的影响见[Nano Banana 2 思考级别怎么选：Minimal、High 与 API 设置](/zh/posts/nano-banana-2-thinking-level)。

### 不要让重试次数相乘

官方 SDK 默认已经带自动重试。以 Python SDK 为例，它会对超时、网络问题、`429` 和 `5xx` 自动重试最多 4 次，初始间隔约 1 秒，最长间隔 60 秒。如果在 SDK 外面再套一层 4 次的重试，一次业务调用最多会发出 4 × (1 + 4) = 20 次请求，每一次都占配额。两层之间只保留一层重试。

直接用 REST 调用时，可以参考下面的 Python 示例。它把一次响应归到六种动作之一，只对 `408`、`429`（每日配额除外）和 `5xx` 退避，次数和总时长都有上限；Interactions API 与 generateContent 的响应都能识别。依赖 `requests`，`url`、`headers`、`payload` 按上面 curl 的内容填写：

```python
import random
import time

import requests

RETRY_HTTP = {408, 429, 500, 502, 503, 504}
STOP_REASONS = {
    "SAFETY", "PROHIBITED_CONTENT", "BLOCKLIST", "SPII", "RECITATION",
    "IMAGE_SAFETY", "IMAGE_PROHIBITED_CONTENT", "IMAGE_RECITATION", "IMAGE_OTHER",
    "LANGUAGE", "CONTENT_BLOCKED", "PUP_LIMITED_DISABLED",
}


def classify(status: int, body: dict) -> dict:
    """把一次响应归到一个动作：ok / backoff / wait_reset / fix / stop / inspect。"""
    err = body.get("error") if isinstance(body, dict) else None
    if status >= 400 or err:
        err = err or {}
        # Interactions API 的 code 是小写字符串；generateContent 的 code 是数字，状态名在 status
        code = err.get("code") if isinstance(err.get("code"), str) else err.get("status", "")
        message = err.get("message", "")
        if code == "quota_exceeded":
            return {"action": "wait_reset", "code": code, "message": message}
        if status in RETRY_HTTP:
            return {"action": "backoff", "code": code or status, "message": message}
        if "location is not supported" in message:
            return {"action": "stop", "code": code or status, "message": message}
        return {"action": "fix", "code": code or status, "message": message}

    # Interactions API：图片在 steps[].content[] 里，type 为 image
    if "steps" in body or "status" in body:
        images = [
            c for s in body.get("steps") or [] for c in s.get("content") or []
            if c.get("type") == "image" and c.get("data")
        ]
        if images:
            return {"action": "ok", "images": images}
        codes = [str(e.get("code", "")) for e in body.get("errors") or []]
        blocked = any(c.upper() in STOP_REASONS for c in codes)
        return {"action": "stop" if blocked else "inspect",
                "status": body.get("status"), "codes": codes}

    # generateContent：先看有没有候选，再看 parts 和 finishReason
    candidates = body.get("candidates") or []
    if not candidates:
        reason = (body.get("promptFeedback") or {}).get("blockReason")
        return {"action": "stop", "blockReason": reason}
    cand = candidates[0]
    parts = (cand.get("content") or {}).get("parts") or []
    images = [p["inlineData"] for p in parts if p.get("inlineData")]
    if images:
        return {"action": "ok", "images": images}
    reason = cand.get("finishReason")
    return {
        "action": "stop" if reason in STOP_REASONS else "inspect",
        "finishReason": reason,
        "finishMessage": cand.get("finishMessage"),
        "text": " ".join(p.get("text", "") for p in parts)[:200],
        "usage": body.get("usageMetadata"),
    }


def generate_with_retry(url, headers, payload, max_attempts=4, budget_s=300):
    """只对暂态错误退避重试，次数和总时长都有上限。
    客户端超时会直接抛出异常：此时服务端结果未知，不自动重发。"""
    deadline = time.monotonic() + budget_s
    for attempt in range(1, max_attempts + 1):
        resp = requests.post(url, headers=headers, json=payload, timeout=(10, 240))
        try:
            body = resp.json()
        except ValueError:
            body = {}
        result = classify(resp.status_code, body)
        result["http_status"] = resp.status_code
        if result["action"] != "backoff" or attempt == max_attempts:
            return result
        delay = min(2 ** (attempt - 1), 30) * random.uniform(1.0, 1.5)
        if time.monotonic() + delay > deadline:
            return result
        time.sleep(delay)
```

几个动作的含义：`fix` 是改请求、密钥或账单后再发；`wait_reset` 是等每日配额重置；`stop` 是内容拦截、账户受限或地区不支持，原样重试没有意义；`inspect` 是 200 却没图、原因不在拦截列表里（例如 `NO_IMAGE`），需要人工看返回的文字和 `finishMessage`。generateContent 的 `429` 都会被归为 `backoff`，如果退避几轮仍然失败，按上一节的方法判断是不是每日配额或消费限速。

## HTTP 200 OK 却没有图片：NO_IMAGE、IMAGE_SAFETY 等原因

这是最容易被当成“接口坏了”的情况。请求本身成功了，只是这次生成没有产出图片，原因写在响应里。

### generateContent：先看有没有候选，再看 blockReason

[generateContent 参考](https://ai.google.dev/api/generate-content?hl=zh-cn)规定，API 要么返回全部候选，要么一个都不返回；完全没有 `candidates` 只说明提示本身有问题，这时看 `promptFeedback.blockReason`：

- `SAFETY`：出于安全原因屏蔽了提示，查看 `safetyRatings` 了解是哪个类别。
- `OTHER`：原因未知。故障排查文档补充说，看到 `BlockedReason.OTHER` 时，请求或回复可能违反了服务条款，或属于不支持的用法。参考图被拦时也可能出现在这里。
- `BLOCKLIST`、`PROHIBITED_CONTENT`：包含屏蔽名单里的词或禁止内容。
- `IMAGE_SAFETY`：因不安全的图片生成内容被屏蔽。

有候选但没有图片时，看候选的 `finishReason`。和图片有关的几个值（含义参照官方中文文档）：

| finishReason | 含义 | 下一步 |
|---|---|---|
| `NO_IMAGE` | 模型本应生成图片，但却未生成任何图片 | 读返回的文字；确认请求里要了图片输出，提示词明确要求生成或修改图片；用最小请求对比 |
| `IMAGE_SAFETY` | 由于生成的图片包含违规内容，生成已停止 | 改提示词或参考图 |
| `IMAGE_PROHIBITED_CONTENT` | 生成的图片包含其他禁止的内容 | 改提示词或参考图 |
| `IMAGE_RECITATION` | 因存在重复内容而停止 | 让提示和参考图更有独创性 |
| `IMAGE_OTHER` | 其他杂项问题导致停止 | 简化输入后对比 |
| `PUP_LIMITED_DISABLED` | 账户因违反禁止使用政策而受限或停用 | 属于账户问题，改提示词无效 |

返回了文字、`finishReason` 是 `STOP`，却没有 `inlineData`，往往是模型只回了文字，先检查请求里的输出类型和提示词有没有明确要求出图。

### Interactions API：看 status、errors 和图片块

Interactions API 把 `safety`、`prohibited_content`、`image_safety`、`image_prohibited_content`、`image_recitation`、`image_other`、`content_blocked` 等列为“生成被拦截”类代码，官方建议是修改输入后再试；`no_image` 则归在生成错误里，含义是模型未能生成图片。拿到响应后，检查 `steps` 里有没有 `type` 为 `image` 的块，再看 interaction 的 `status` 和 `errors`。

### 把安全设置调低有用吗

多半没有用。按 [安全设置文档](https://ai.google.dev/gemini-api/docs/safety-settings)，可调的四类过滤（骚扰、仇恨言论、色情、危险内容）默认已经关闭，而儿童安全等核心保护始终生效、不能调整。由此推断，把安全阈值改成 `BLOCK_NONE` 一般不会让 `IMAGE_SAFETY` 或 `PROHIBITED_CONTENT` 消失。能做的是改写提示词、换掉触发拦截的参考图，而不是用重试去碰运气。提示词层面的具体改法见[Gemini 不出图或 IMAGE_SAFETY 怎么排查？修复思路汇总](/zh/posts/gemini-image-silent-failure-image-safety-fix)。

## 生成失败的请求会不会扣费

分三种情况看：

- **返回 400 或 500 的请求**：计费文档写明不收 token 费用，但**仍然计入配额**。所以对 `400` 反复重试，钱不多花，额度却在消耗。
- **HTTP 200 但以 `IMAGE_SAFETY`、`NO_IMAGE` 结束的请求**：Google 的计费和价格页面都没有说明怎么计费。可以核对的办法是看这类响应里的 `usageMetadata`（`promptTokenCount`、`candidatesTokenCount`、`thoughtsTokenCount`），再和 AI Studio 的账单记录对照。
- **客户端超时、没拿到响应的请求**：服务端是否完成、是否计费，文档没有说明。

通过第三方网关调用时，失败怎么收费由网关自己规定，和 Google 的规则不同。比如 laozhang.ai（新加坡 YingTu Technology Pte. Ltd. 运营的 API 网关）的 [Nano Banana 文档](https://docs.laozhang.ai/api-capabilities/nano-banana-image)写明：它对 `gemini-3.1-flash-image` 按次收费，2026 年 9 月 24 日价格配置为每次 $0.055，是服务商自定的价格；HTTP 200 但没有图片（包括上游安全拦截）按一次调用扣费；客户端超时时服务端可能已经扣费，重试前要先查调用日志；返回 `429` 或 `503`、没有进入生成的请求通常不扣费。它只接受 Gmail 注册，能否开通以企业白名单审核为准。网关返回的错误代码与 Google 原始错误的对应关系，要以网关自己的文档和调用日志为准。

## 什么时候停止重试，求助时带什么

![重试与停止流程图：已保存原始证据后按错误类型或原因分成五列，分别是 400、429/503/408/5xx、NO_IMAGE、安全或 policy 拦截、timeout，其中暂态错误一列进入指数退避加 jitter、带尝试次数上限和总时间预算的循环，底部是硬停止门和携带证据包的升级流程](https://www.aifreeapi.com/posts/zh/nano-banana2-api-error-codes/img/retry-timeline.webp)

上图是一个通用的停止与升级流程。放到 Nano Banana 2 上，还要补一条：`429 quota_exceeded` 不进退避循环，而是等每日配额重置。遇到以下任何一种情况，就停止自动重试：

- `400`、`401`、`402`、`403`、`404`，包括地区不支持的 `FAILED_PRECONDITION`；
- `429 quota_exceeded`，或者 AI Studio 显示已到月度消费上限；
- `IMAGE_SAFETY`、`PROHIBITED_CONTENT`、`blockReason` 等内容拦截，以及 `PUP_LIMITED_DISABLED`；
- `NO_IMAGE` 还没用最小请求对比过；
- 退避达到次数上限或总时长预算，`503` 仍在持续；
- 客户端超时，而服务端结果还没确认。

需要向 Google 支持或团队求助时，一句“还是不行”解决不了问题。准备一份去掉密钥和敏感内容的记录：

- 时间范围（注明时区）、调用的接口（Interactions API 或 generateContent）、完整 URL 路径、API 版本和模型 ID；
- HTTP 状态码、`error.code` / `status`、完整的 `message`；
- 响应里的 interaction `id` 或 `responseId`、`modelVersion`、`usageMetadata`；
- `finishReason`、`finishMessage`、`promptFeedback`，以及返回了哪些类型的内容；
- 每次尝试的耗时、客户端超时设置、SDK 和外层各自的重试次数；
- 同一项目、同一模型下最小请求是否成功。

恢复的判断标准也要明确：在你实际使用的同一条链路上，最小请求返回了可以解码的图片，然后原来的批量任务在受控并发下也能跑完。只看到 HTTP 200，或者只是日志里不再出现 `NO_IMAGE`，还不够。

## 常见问题

### Gemini API 在国内可以用吗？

官方不支持。Gemini API 与 AI Studio 的可用地区列表里没有中国大陆、香港和澳门，在这些地区发起的调用会被拒绝，重试无效。Google 建议不在列表里的用户看 Gemini Enterprise Agent Platform，但该平台是否面向中国大陆客户提供服务，公开页面没有说明。

### 同一个项目换一个 API key，能躲开 429 吗？

不能。速率限制按项目计算，不按 key 计算。想提高上限，要么等层级随消费自动升级，要么在 AI Studio 申请提额；如果是 `quota_exceeded`，就等太平洋时间午夜重置。

### Gemini API 报 503 要等多久才能恢复？

Google 没有公布恢复时间。按 1 秒、2 秒、4 秒、8 秒的节奏加随机抖动退避，设好次数上限；持续失败时降低并发或推迟批量任务，并记录时间范围和响应 `id`，方便向支持反馈。

### 用了很久的 gemini-3.1-flash-image-preview 突然报 404，怎么办？

预览 ID 已在 2026 年 6 月 25 日停止服务，把模型名改成 `gemini-3.1-flash-image`。改名后如果变成 `400`，按当前的图片生成文档核对参数，比如 `image_size` 必须用大写 `K`。

### 选 Nano Banana 2 还是 Pro，报错和处理方式有区别吗？

错误代码和处理方式在两个模型上是一样的，差别在价格、画质和速度，因此同样的消费限速下能出的图片数量也不同。怎么选见[Nano Banana 2 vs Pro 怎么选：价格、画质、速度与场景](/zh/posts/nano-banana-2-vs-nano-banana-pro)。
