# Nano Banana 2 blockReason OTHER：官方只写「原因未知」，该查什么

> Google 对 blockReason OTHER 只写「原因未知」：提示词被拦、没有候选，不知是哪条规则。别指望 BLOCK_NONE，先存证据，改一个变量再测，仍被拦就上报。

- URL: https://blog.laozhang.ai/zh/posts/nano-banana-2-blockreason-other
- Published: 2026-03-09
- Updated: 2026-10-04
- Author: LaoZhang AI Team (https://blog.laozhang.ai/zh/about)
- Topic: 故障排查
- Tags: Nano Banana 2, blockReason OTHER, Gemini API, 图片生成, 错误排查

---
用 `generateContent` 调用 Nano Banana 2（模型 ID `gemini-3.1-flash-image`）或 Nano Banana Pro（`gemini-3-pro-image`），返回里出现 `"promptFeedback": {"blockReason": "OTHER"}`、没有任何候选结果，Google 给出的解释只有一句：**Prompt was blocked due to unknown reasons**，即提示词因未知原因被拦截。

这句话能确定两件事：提示词在生成之前被拦下了，这次调用不会有图片。它不能告诉你的是哪条规则、哪个系统拦的。Google 没有公布 `OTHER` 背后的内容类别，也没有公布安全系统分几层；把 OTHER 归到某一类内容，都是推测。

因此能做的事情很具体：

- 先确认是哪一种 OTHER：`promptFeedback.blockReason`、候选里的 `finishReason: "OTHER"` 和 `finishReason: "IMAGE_OTHER"` 是三回事。
- 不要指望把安全设置调成 `BLOCK_NONE` 来解决。
- 保存 `responseId`、`modelVersion`、`usageMetadata` 和请求条件，让问题可以复现、可以上报。
- 代码里把它当成独立的结果：不当成功，不无限重试。
- 原样重试一次，再一次只改一个变量测试；稳定被拦就停下，带着证据向 Google 反馈。

## blockReason OTHER 的官方定义：提示词被拦，原因未知

Google 的 [GenerateContent API 参考](https://ai.google.dev/api/generate-content#BlockReason)（截至 2026 年 10 月 4 日，页面更新于 2026 年 9 月 23 日）对 `PromptFeedback.blockReason` 的说明是：设置了这个字段，表示提示词被拦截，**不返回任何候选**，并建议改写提示词。同一页写明，只有提示词本身出了问题时，响应才会完全没有候选。

`BlockReason` 枚举里每个值的原文含义如下：

| 值 | Google 的说明 | 你能据此知道什么 |
| --- | --- | --- |
| `SAFETY` | 因安全原因被拦，查看 `safetyRatings` 了解是哪个安全类别 | 可以从 `safetyRatings` 找到类别 |
| `OTHER` | 因未知原因被拦 | 只知道被拦，不知道依据 |
| `BLOCKLIST` | 包含术语屏蔽列表里的词 | 是词表命中 |
| `PROHIBITED_CONTENT` | 包含禁止内容 | 是禁止内容 |
| `IMAGE_SAFETY` | 因不安全的图片生成内容而拦截候选 | 与图片生成内容有关 |
| `BLOCK_REASON_UNSPECIFIED` | 默认值，不使用 | 不代表被拦 |

和 `SAFETY` 对比就能看出 `OTHER` 的特殊之处：`SAFETY` 指向一个可以查的字段，`OTHER` 什么都不指向。

2025 年 12 月 29 日，Google AI Developers Forum 上有开发者反映 Nano Banana Pro 每 5 次请求就有 1 次返回 OTHER。Google 的 Logan Kilpatrick 在[“blockReason: OTHER”论坛帖](https://discuss.ai.google.dev/t/blockreason-other/113496)里回复，团队正在重新设计「Other」类错误，并承认「现在这种设置方式没什么帮助」，目标是 2026 年 1 月上旬改进。帖子之后没有更新；截至 2026 年 10 月 4 日，API 参考里 `OTHER` 的定义仍是「原因未知」。

## promptFeedback 还是 finishReason：三种 OTHER 在 JSON 的哪里

「出图失败，报 OTHER」可能对应三个不同字段，处理方式也不同：

| 你看到的 | 在响应中的位置 | 有没有候选 | Google 的说明 | 该怎么处理 |
| --- | --- | --- | --- | --- |
| `blockReason: "OTHER"` | 顶层 `promptFeedback` | 没有 | 提示词因未知原因被拦 | 按下文的证据和处理顺序 |
| `finishReason: "OTHER"` | `candidates[i]` | 有，但停止了 | 未知原因 | 同样当作失败，看 `finishMessage` |
| `finishReason: "IMAGE_OTHER"` | `candidates[i]` | 有，但停止了 | 图片生成因其他杂项问题停止 | 当作失败，看 `finishMessage` |

提示词级拦截的响应大致是这个形状（示意，省略了具体数值）：

```text
{
  "promptFeedback": {
    "blockReason": "OTHER"
  },
  "usageMetadata": { ... },
  "modelVersion": "...",
  "responseId": "..."
}
```

没有 `candidates`，所以直接读 `candidates[0]` 的代码会在这里报错。用 Python SDK 时，对应的属性是 `response.prompt_feedback.block_reason`。

候选级的 OTHER 说明提示词通过了，但生成没有正常结束。候选上可能带有 `finishMessage`，Google 说明它会补充停止原因的细节，有就一定要记录。

![三种 OTHER 在响应 JSON 中的位置：promptFeedback.blockReason 表示提示词被拦且没有候选，候选里的 finishReason OTHER 与 IMAGE_OTHER 表示生成中途停止，都要当作失败并记录 finishMessage](https://blog.laozhang.ai/posts/zh/nano-banana-2-blockreason-other/img/other-field-map.webp)

如果 HTTP 200、有候选、`finishReason` 是 `STOP` 或 `NO_IMAGE` 却没有图片，那是另一类问题，按 [Nano Banana API 不出图：按返回字段逐项排查](https://blog.laozhang.ai/zh/posts/nano-banana-2-200-ok-no-image) 处理。429、503 之类的 HTTP 错误见 [Nano Banana API 报错：先分清 429、503、无图像和请求被拒](https://blog.laozhang.ai/zh/posts/nano-banana-pro-error)。

## 设成 BLOCK_NONE 能解决 OTHER 吗：不能指望

Google 的[安全设置文档](https://ai.google.dev/gemini-api/docs/safety-settings)（截至 2026 年 10 月 4 日）写明了可调整的范围：骚扰、仇恨言论、露骨色情、危险内容这四个类别可以设阈值；危害儿童安全等核心危害由内置保护**始终拦截**，不能调整。文档还写明，Gemini 2.5 和 3 系列模型不设置阈值时，默认就是 `OFF`。

由此可以推断两点。第一，`BLOCK_NONE` 和 `OFF` 只作用于这四个可调类别，而 `OTHER` 恰恰没有告诉你是哪个类别，没有理由认为放宽阈值能改变它。第二，当前模型默认已经是 `OFF`，你再把阈值设成 `BLOCK_NONE`，多数情况下并没有放宽什么。

这只是推断，Google 没有直接说「BLOCK_NONE 对 OTHER 无效」，但有开发者的观察与之一致：2026 年 2 月 6 日，一个团队在 [Stack Overflow 提问](https://stackoverflow.com/questions/79884545)，称涉及知名公众人物的提示词返回 `blockReason: OTHER`，把所有类别设为 `BLOCK_NONE` 后依旧被拦。

另外，文档提醒使用较宽松安全设置的应用可能会受到审核。为了「试试看」把所有阈值放到最低，没有收益，还要承担这个代价。

## 参考图、公众人物、间歇出现：开发者报告过的 OTHER

下面是带日期的个人报告，不是 Google 公布的规则。它们说明 OTHER 可能间歇出现，也可能和参考图、真实人物同时出现，但都不能证明原因。

- **间歇出现**：2025 年 12 月 29 日，[论坛帖](https://discuss.ai.google.dev/t/blockreason-other/113496)中有开发者通过 AI Studio 的 API 使用 Nano Banana Pro，约每 5 次请求有 1 次返回 OTHER。
- **只要带参考图就被拦**：2026 年 5 月 7 日，[另一个论坛帖](https://discuss.ai.google.dev/t/persistent-other-block-reason-error-on-nano-banana-pro-gemini-3-pro-image-preview-with-reference-images/143901)反映在 Google AI Studio 里用 `gemini-3-pro-image-preview` 时，每次附上参考图都立刻以 Other 原因被拦。Google 工作人员私信索要细节，帖子里没有公开结论。
- **涉及公众人物**：上面那个 Stack Overflow 问题里，提示词点名知名公众人物时返回 OTHER；把人名换成描述性的说法，依然被拦。

至于是不是地区问题：Google 没有公布 `OTHER` 与地区的关系。那个问题下有评论认为 OTHER 与地区合规无关、而是针对真实人物的策略，但评论没有给出出处，只能当作一种说法。切换代理或地区来规避拦截，属于绕开服务方的控制，不是排查方法。

最后两条报告用的是 preview 模型 ID。`gemini-3.1-flash-image-preview` 和 `gemini-3-pro-image-preview` 已于 2026 年 6 月 25 日停用（[Google 弃用页](https://ai.google.dev/gemini-api/docs/deprecations)），现在应改用 `gemini-3.1-flash-image` 与 `gemini-3-pro-image`。

## 被拦截后要保存的证据：responseId、modelVersion 与请求条件

`OTHER` 本身不带信息，能让问题被诊断的只有你自己留下的记录。Google 没有公布针对 OTHER 的上报清单，下面这份是按响应字段整理的，向论坛或支持渠道反馈时基本够用：

| 记录项 | 从哪里拿 | 用途 |
| --- | --- | --- |
| `responseId` | 响应顶层 | 标识这一次响应 |
| `modelVersion` | 响应顶层 | 确认实际处理请求的模型版本 |
| 请求里的模型 ID | 你的代码 | 排除用错或用了已停用的 ID |
| `promptFeedback` 整个对象 | 响应顶层 | 包括 `blockReason` 和可能存在的 `safetyRatings` |
| 每个候选的 `finishReason`、`finishMessage` | `candidates[i]` | 区分三种 OTHER |
| `usageMetadata` | 响应顶层 | 看 `promptTokenCount`、`candidatesTokenCount`、`thoughtsTokenCount`，也用于核对费用 |
| 请求时间，统一用 UTC | 你的日志 | 对应服务端记录，判断是否集中在某段时间 |
| 是否带参考图、带了几张 | 你的代码 | 对应参考图相关的报告 |
| 响应模态与安全设置 | 请求配置 | 说明你没有改动或改动了什么 |
| 复现情况 | 你的测试 | 例如「同一请求 10 次中 3 次被拦」 |

提示词原文和参考图只保存在自己的系统里。需要公开发帖时，提交脱敏后的版本：去掉客户信息、真实人名和私人照片，只保留足以复现的部分。

## 用 Python 把 blockReason OTHER 单独分类

下面这个脚本读取一份保存下来的 `generateContent` 响应 JSON（REST 接口原样返回的 camelCase 字段），把它归为五种状态之一：

| 状态 | 含义 | 代码该怎么做 |
| --- | --- | --- |
| `api_error` | 响应里有 `error` | 按 HTTP 错误处理，见上文报错页 |
| `prompt_blocked` | `blockReason` 有值且不是 `BLOCK_REASON_UNSPECIFIED`，包括 `OTHER` 和将来新增的值 | 不重试循环，记录证据，提示用户修改请求 |
| `candidate_stopped` | 有候选，但 `finishReason` 不是 `STOP` | 当作失败，记录 `finishMessage` |
| `image_ready` | 至少一张有效图片，且所在候选 `finishReason` 是 `STOP` | 保存图片 |
| `no_image` | 其他所有没有可用图片的情况 | 按不出图排查 |

图片要过几道检查才算有效：跳过 `thought: true` 的思考部分，MIME 必须是 PNG、JPEG 或 WebP，base64 能解码且不为空，Pillow 能打开，实际格式与 MIME 一致；只有 `finishReason` 为 `STOP` 的候选里的图片才会被采用。

```python
import base64
import binascii
import io
import json
import sys
from pathlib import Path

from PIL import Image, UnidentifiedImageError

FORMATS = {"image/png": "PNG", "image/jpeg": "JPEG", "image/webp": "WEBP"}


def as_dict(value):
    return value if isinstance(value, dict) else {}


def as_list(value):
    return value if isinstance(value, list) else []


def inspect_response(response):
    if not isinstance(response, dict):
        raise ValueError("响应的顶层必须是 JSON 对象")

    feedback = as_dict(response.get("promptFeedback"))
    block = feedback.get("blockReason")
    report = {
        "status": "no_image",
        "response_id": response.get("responseId"),
        "model_version": response.get("modelVersion"),
        "usage": response.get("usageMetadata"),
        "block_reason": block,
        "prompt_safety_ratings": as_list(feedback.get("safetyRatings")),
        "candidates": [],
        "images": [],
    }
    if response.get("error"):
        report["status"] = "api_error"
        return report
    # 提示词级拦截：OTHER、SAFETY 以及将来新增的原因都归到这里
    if block and block != "BLOCK_REASON_UNSPECIFIED":
        report["status"] = "prompt_blocked"
        return report

    candidates = as_list(response.get("candidates"))
    for ci, raw_candidate in enumerate(candidates):
        candidate = as_dict(raw_candidate)
        reason = candidate.get("finishReason")
        entry = {
            "index": ci,
            "finish_reason": reason,
            "finish_message": candidate.get("finishMessage"),
            "safety_ratings": as_list(candidate.get("safetyRatings")),
            "image_issues": [],
        }
        report["candidates"].append(entry)
        content = as_dict(candidate.get("content"))
        for pi, raw_part in enumerate(as_list(content.get("parts"))):
            part = as_dict(raw_part)
            # 跳过思考过程中的图片
            if part.get("thought"):
                continue
            blob = as_dict(part.get("inlineData"))
            if not blob:
                continue
            mime = blob.get("mimeType")
            encoded = blob.get("data")
            problem = None
            data = b""
            if not isinstance(mime, str) or mime not in FORMATS:
                problem = "unsupported_mime"
            elif not isinstance(encoded, str) or not encoded:
                problem = "empty_or_missing_data"
            else:
                try:
                    data = base64.b64decode(encoded, validate=True)
                    if not data:
                        raise ValueError("empty bytes")
                    with Image.open(io.BytesIO(data)) as img:
                        actual_format = img.format
                        img.load()
                    if actual_format != FORMATS[mime]:
                        raise ValueError("MIME does not match image format")
                except (ValueError, binascii.Error, OSError,
                        UnidentifiedImageError, Image.DecompressionBombError):
                    problem = "invalid_image_data"
            if problem:
                entry["image_issues"].append({"part": pi, "reason": problem})
            elif reason == "STOP":
                report["images"].append({
                    "candidate": ci, "part": pi, "mime_type": mime, "data": data
                })
            else:
                # 候选不是正常结束（如 OTHER），即使带图也不直接采用
                entry["image_issues"].append({
                    "part": pi, "reason": "finish_reason_requires_review"
                })

    if report["images"]:
        report["status"] = "image_ready"
    elif any(c["finish_reason"] not in (None, "STOP", "FINISH_REASON_UNSPECIFIED")
             for c in report["candidates"]):
        report["status"] = "candidate_stopped"
    return report


if __name__ == "__main__":
    response = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))
    result = inspect_response(response)
    # 不把图片二进制和完整日志打到终端，只输出用于确认的概要
    print(json.dumps({
        "status": result["status"],
        "block_reason": result["block_reason"],
        "finish_reasons": [c["finish_reason"] for c in result["candidates"]],
        "image_count": len(result["images"]),
        "image_issues": [c["image_issues"] for c in result["candidates"]],
    }, ensure_ascii=False, indent=2))
```

用法：先 `pip install pillow`，把响应保存成 `response.json`，再运行 `python3 inspect_response.py response.json`。对一份只有 `promptFeedback.blockReason: "OTHER"` 的响应，输出里 `status` 是 `prompt_blocked`，`block_reason` 是 `OTHER`。在自己的服务里直接调用 `inspect_response()`，返回的字典里已经带着 `response_id`、`model_version` 和 `usage`，可以直接写进日志。

需要说明的是，这个脚本是用 29 个手工构造的 JSON 用例测试的（Python 3.12.1、Pillow 12.0.0，2026 年 10 月 4 日），全部通过，没有调用 Gemini API。用例覆盖了缺少或为空的 `candidates`、`parts` 为 null、只有文字、提示词级 `OTHER`/`SAFETY`/未知新值、候选级 `OTHER`/`NO_IMAGE`、空的或非法的 base64、伪造的 PNG、MIME 错误、思考图片、`OTHER` 但带图、第二个候选才有效、两张图、API 错误和顶层不是对象等情况。它证明的是脚本的分支判断正确，不能证明 Google 在什么情况下返回 OTHER。

## 重试、改一个变量还是上报：OTHER 的处理顺序

拿到 `prompt_blocked` 之后，按下面的顺序走：

1. **原样重试一次。** 2025 年 12 月那份约五分之一请求返回 OTHER 的报告说明，OTHER 可能间歇出现。重试一次能初步区分偶发与稳定。代码里不要写无限重试或高频循环，被拦的请求反复发送不会带来新信息。
2. **偶发：记录频率，继续观察。** 把每次被拦的证据存下来。如果比例突然升高，或者原本稳定的业务请求开始成批被拦，这本身就是值得上报的现象。
3. **稳定被拦：一次只改一个变量再测。** 例如先去掉参考图，或去掉真实人名，或把一次提出的多个要求缩减到核心要求。每次只动一处，记下哪一项改变了结果。这样做是为了定位触发条件、写出可复现的报告，也帮你判断这个需求在产品里能不能做，不是为了把被拦的内容换个说法送过去。
4. **该停的时候停。** 请求涉及真实人物、未成年人等敏感对象，几种合理改法都稳定返回 OTHER，就按「当前不支持」处理，在产品里给用户明确提示。把人名改成影射、把被拦的请求拆成几段分别生成，属于绕开安全措施，而且上面的 Stack Overflow 报告显示，换成描述性说法也照样被拦。
5. **普通内容稳定被拦：带证据上报。** 商品图、自己的照片编辑这类普通请求稳定返回 OTHER，或者之前能用、突然全部被拦，就到 [Google AI Developers Forum](https://discuss.ai.google.dev/) 发帖，附上前面那张表里的记录和脱敏后的复现用例。

![blockReason OTHER 的处理顺序：原样重试一次，偶发就记录频率继续观察，稳定被拦就一次只改一处再测，涉及敏感对象时停下，普通内容仍被拦则带证据上报](https://blog.laozhang.ai/posts/zh/nano-banana-2-blockreason-other/img/handling-order.webp)

面向终端用户时，`prompt_blocked` 应该显示成明确的失败，例如「这次请求没有生成图片，可以修改描述后再试」，而不是转圈等待或静默返回空白。

## blockReason OTHER 会不会扣费：看 usageMetadata 和账单

Google 没有公开说明返回 `blockReason`、没有候选的请求是否按图片计费，也没有说明它免费。所以「照样全额收费」和「拦截不收费」都下不了结论。

能核对的只有两处：这次调用自己的 `usageMetadata`（`promptTokenCount`、`candidatesTokenCount`、`thoughtsTokenCount`），以及项目的账单报表。把被拦请求的 `responseId` 和时间记下来，对账时就能逐笔对照。

通过第三方 API 网关调用时，计费按网关自己的规则。以 LaoZhang API 为例，[它的 Nano Banana 文档](https://docs.laozhang.ai/en/api-capabilities/nano-banana-image)写明 HTTP 200 但没有图片按一次调用计费（截至 2026 年 10 月 4 日）。

*说明：[laozhang.ai 是我们自己的服务](https://blog.laozhang.ai/zh/about#laozhang)，其价格是平台报价，不是独立比较的结论。*

## Interactions API、Gemini 应用和其他报错：与 blockReason OTHER 的区别

### Interactions API 返回的也是 blockReason 吗？

不是同一个结构。Interactions API 的响应用 `steps` 和 `status` 表达结果，没有 `candidates` 和 `promptFeedback`，自定义安全设置在这个接口里也不可用。前面讲的字段都属于 `generateContent`；用 Interactions API 时，按 [Nano Banana API 不出图：按返回字段逐项排查](https://blog.laozhang.ai/zh/posts/nano-banana-2-200-ok-no-image) 里对应的部分检查。

### 在 Gemini 应用里出图失败，和 blockReason OTHER 有关吗？

Gemini 应用不显示 API 字段，排查路线也不同，见 [Gemini 里 Nano Banana Pro 用不了？先按应用路线排查](https://blog.laozhang.ai/zh/posts/nano-banana-pro-not-working-in-gemini)。

### 503 和 thought signature 错误也算 OTHER 吗？

不算。503「模型过载」是 HTTP 错误，不会出现在 `promptFeedback` 里，见 [Nano Banana 2 503「模型过载」修复指南：6 种已验证解决方案（2026）](https://blog.laozhang.ai/zh/posts/nano-banana-2-503-overloaded-fix)；`MISSING_THOUGHT_SIGNATURE` 是另一个 `finishReason` 值，表示请求里缺少思考签名，见 [Nano Banana 2 Thought Signature 错误：全场景修复指南（2026）](https://blog.laozhang.ai/zh/posts/nano-banana-2-thought-signature-error)。

## 参考来源

本文引用的外部页面，按正文出现顺序排列。最后更新于 2026-10-04。

- [GenerateContent API 参考](https://ai.google.dev/api/generate-content) (ai.google.dev)
- [“blockReason: OTHER”论坛帖](https://discuss.ai.google.dev/t/blockreason-other/113496) (discuss.ai.google.dev)
- [安全设置文档](https://ai.google.dev/gemini-api/docs/safety-settings) (ai.google.dev)
- [Stack Overflow 提问](https://stackoverflow.com/questions/79884545) (stackoverflow.com)
- [另一个论坛帖](https://discuss.ai.google.dev/t/persistent-other-block-reason-error-on-nano-banana-pro-gemini-3-pro-image-preview-with-reference-images/143901) (discuss.ai.google.dev)
- [Google 弃用页](https://ai.google.dev/gemini-api/docs/deprecations) (ai.google.dev)
- [Google AI Developers Forum](https://discuss.ai.google.dev/) (discuss.ai.google.dev)
