|

Nano Banana Pro 报错 Unsupported file URI type 完整排查:5 大原因与一次性修复方案

最近有客户在调用 Nano Banana Pro(模型 ID:gemini-3-pro-image-preview)进行图生图时,遇到了一个看起来很 "Google 风格" 的 400 报错:

{
  "status_code": 400,
  "error": {
    "message": "Unsupported file URI type: {{ $json.imageUrls }}. File URI must be a File API (e.g. https://generativelanguage.googleapis.com/files/<id>), Youtube (e.g. https://www.youtube.com/watch?v=<id>), or HTTPS (e.g. http://path/to/file).), or a valid gURI (e.g. gs://bucket/object",
    "type": "",
    "code": 400
  }
}

这条 Nano Banana Pro 报错 信息其实已经把"凶手"指出来了:Unsupported file URI type: {{ $json.imageUrls }}。请注意 {{ $json.imageUrls }}未被替换的 n8n 模板变量原文——也就是说,客户在工作流里写了一个动态表达式,但是这个表达式根本没有被引擎渲染成真正的 URL,而是被当成字符串原样塞进了 Gemini API 的 fileUri 字段。Google 这边自然没法识别一个长成 {{ ... }} 的 URI,于是直接拒绝了请求。

本文基于这条真实报错,以及 Google 官方文档对 gemini-3-pro-image-preview 输入格式的要求,系统拆解 5 类最常见的触发场景,并给出每一种场景的最小可复现代码与一次性修复方案。读完之后,你应该能够在 5 分钟之内定位并修好任何一条出现 Unsupported file URI type 的失败请求。

nano-banana-pro-unsupported-file-uri-type-error-fix 图示

Nano Banana Pro 报错核心信息一览

在动手改代码之前,我们先用一张表把这条报错的关键信息和官方对输入 URI 的允许格式锁定到一屏之内。

维度 关键事实
模型 ID gemini-3-pro-image-preview(Nano Banana Pro 在 Gemini API 中的正式名)
报错 HTTP 状态 400(Bad Request,客户端参数错误)
报错关键字段 Unsupported file URI type
真正问题位置 请求 body 中的 fileData.fileUri 字段
报错里出现的字面量 {{ $json.imageUrls }}(未被渲染的 n8n 表达式)
Gemini 接受的 URI 类型 File API URI / YouTube URL / 公网 HTTPS URL / GCS gs:// URI
Gemini 接受的图片格式 JPEG、JPG、PNG、WEBP、HEIF
Nano Banana Pro 输入支持外部 URL? ✅ 支持(Gemini 2.5+ 模型起原生支持公网 HTTPS / 预签名 URL)
大概率根因 n8n / Make / Zapier 等低代码工作流的模板变量未被替换

🎯 快速排查建议:如果你的客户不愿意把完整请求 body 给你看,你可以让他先在 API易 apiyi.com 控制台用同一个 gemini-3-pro-image-preview 模型 + 同一张参考图复现一次成功的调用,然后再把失败请求与成功请求的 body 做 diff,这是最快锁定 Nano Banana Pro 报错 的方式。

Nano Banana Pro 报错 Unsupported file URI type 的 5 大成因

把所有真实案例归类后,这条 Unsupported file URI type 报错可以收敛到 5 个典型原因。我们按"出现频率"从高到低排序。

原因 1:n8n / Make / Zapier 的模板变量没有被渲染

这是当前这条具体报错的第一嫌疑人{{ $json.imageUrls }} 是 n8n 表达式语法,正常情况下应该在执行前被替换成上一步节点输出的真实 URL,例如 https://cdn.example.com/uploads/abc.jpg。但有几种典型情况会让这个替换失败:

  1. HTTP Request 节点的 Body 字段没有点 "Expression" 模式,而是写成了 "Fixed" 模式,导致整段 JSON 被当成纯文本字符串发送;
  2. JSON Body 用了双层引号嵌套,n8n 误以为表达式是字符串内容的一部分,跳过渲染;
  3. 上一步节点的输出结构和你写的路径对不上——例如上一步实际输出的是 imageUrl(单数),你却写了 $json.imageUrls(复数),解析失败后 n8n 把整个表达式原文返回;
  4. Sub-node 中的表达式不会按 Item 迭代,而是固定取第一条,某些输入下变成 undefined,序列化为字符串后变成原文。

判断方法:只要你看到 Gemini 的报错里包含 {{ ... }},就 100% 是这一类问题,因为正常 URL 不可能长成那样。

原因 2:字段名拼写错误,导致传入了 undefined / null

紧随其后的是字段名问题。客户的代码里很可能存在这种情况:

// 上游接口实际返回的字段叫 imageUrl(单数)
const upstream = { imageUrl: "https://cdn.example.com/a.jpg" };

// 但下游写的是 imageUrls(复数,带 s)
fileUri: upstream.imageUrls   // 结果是 undefined

undefined 在被 JSON 序列化或字符串拼接时,会变成 "undefined" 这个字符串,Gemini 同样无法识别,于是抛出和模板变量未渲染几乎一模一样的 400 报错。区别在于报错里出现的字面量是 undefined 而不是 {{ ... }}

原因 3:把数组当成字符串传进了 fileUri

第三类原因常出现在"批量处理多张图"的场景。Gemini API 的 fileData.fileUri 字段只接受单个字符串,不是数组。但很多开发者会这样写:

// ❌ 错误:把数组直接塞进 fileUri
{
  "fileData": {
    "fileUri": ["https://cdn.example.com/a.jpg", "https://cdn.example.com/b.jpg"],
    "mimeType": "image/jpeg"
  }
}

JSON 序列化后这个 fileUri 字段会变成 ["https://...", "https://..."] 字符串,Gemini 解析失败,直接报 Unsupported file URI type。正确做法是为每张图生成一个独立的 parts 元素,而不是把数组塞到一个 fileUri 里。

原因 4:URL 协议或路径格式不被支持

第四类问题属于"格式偏差"。Gemini API 接受的 URI 类型只有 4 种,任何超出范围的写法都会触发同样的报错:

URI 类型 示例 是否被 gemini-3-pro-image-preview 接受
File API 路径 https://generativelanguage.googleapis.com/files/abc123
YouTube URL https://www.youtube.com/watch?v=xxxxx ✅(主要用于视频理解)
公网 HTTPS URL https://cdn.example.com/img.jpg ✅(Gemini 2.5+ 起原生支持)
GCS gs:// URI gs://my-bucket/img.jpg ✅(Vertex AI 路径)
http:// 明文 http://cdn.example.com/img.jpg ⚠️ 部分情况被拒,推荐升级到 HTTPS
file:// 本地路径 file:///Users/me/a.jpg
data:image/...;base64, base64 dataURL ❌(应放到 inlineData)
Pre-signed S3 URL https://bucket.s3.amazonaws.com/...?X-Amz-...
Azure SAS URL https://account.blob.core.windows.net/...?sv=...

如果你直接把本地文件路径、data: 开头的 base64 或者私有内网 URL 塞到 fileUri,无一例外都会触发 Nano Banana Pro 报错

原因 5:URL 可访问但需要鉴权 / 返回非图片

最后一类是"URL 看起来对了,但 Gemini 实际拉不到内容"。常见情况:

  • 私有 OSS / 七牛 / Cloudinary 链接没有公开权限,Gemini 拉到 403;
  • 临时签名 URL 已经过期;
  • URL 返回的不是图片,而是 HTML 页面(例如某些图床的"分享页",而不是直链);
  • URL 重定向跳转到登录页;
  • MIME 类型与 mimeType 字段不匹配。

这类问题有时也会以 Unsupported file URI type 的形式抛出,有时则会变成另一条 400 Invalid or unsupported file uri。两者的修复思路是一样的:用浏览器无痕窗口直接访问这条 URL,看是不是能下载到一张合法的图片,这是最朴素也最有效的方法。

nano-banana-pro-unsupported-file-uri-type-error-fix 图示

Nano Banana Pro 报错的最小复现与一次性修复方案

把 5 大原因看完之后,接下来给出每一种场景下的最小可复现代码 + 修复版本,可以直接复制到你的工作流或后端中替换。

修复 1:n8n 中正确传递 imageUrls 参数

针对客户当前这条 Nano Banana Pro 报错,如果他用的是 n8n 的 HTTP Request 节点,正确的写法应该是这样:

HTTP Request 节点配置:

  • Method: POST
  • URL: https://api.apiyi.com/v1/messages(替换为你的 API易转发地址)
  • Authentication: Header Auth(放上你的 API Key)
  • Body Content Type: JSON
  • Specify Body: 选择 Using JSON(而不是 Using Fields)
  • JSON Body(注意整段 JSON 用表达式模式,即左侧紫色 fx 按钮要点亮):
={
  "model": "gemini-3-pro-image-preview",
  "contents": [
    {
      "parts": [
        { "text": "把这张图变成宫崎骏风格" },
        {
          "fileData": {
            "fileUri": "{{ $json.imageUrls }}",
            "mimeType": "image/jpeg"
          }
        }
      ]
    }
  ]
}

关键点有 3 个:

  1. JSON 字符串前面有 = 号,告诉 n8n 这整段是表达式,需要解析;
  2. "{{ $json.imageUrls }}" 外层必须有双引号,内层 {{ }} 才会被替换成真正的字符串;
  3. 上一步节点必须真的输出名为 imageUrls 的字段;如果它输出的是 imageUrl(单数)或 image_url,要相应改字段名。

只要这 3 点同时满足,Unsupported file URI type 报错就会立刻消失。

修复 2:Python / Node.js 中防止字段名 typo

如果客户用的是后端代码,推荐加一道输入校验,把 typo 暴露在请求 Gemini 之前:

import requests

def call_nano_banana_pro(prompt: str, image_url: str):
    # 防御式校验:在发请求前先把 None / 空串 / 模板字符串拦下来
    if not image_url or not isinstance(image_url, str):
        raise ValueError(f"image_url 必须是非空字符串,当前值: {image_url!r}")
    if image_url.startswith("{{") or "undefined" in image_url:
        raise ValueError(f"image_url 看起来是未渲染的模板变量: {image_url}")
    if not image_url.startswith(("https://", "gs://")):
        raise ValueError(f"image_url 必须是 https:// 或 gs:// 开头: {image_url}")

    payload = {
        "model": "gemini-3-pro-image-preview",
        "contents": [{
            "parts": [
                {"text": prompt},
                {"fileData": {
                    "fileUri": image_url,
                    "mimeType": "image/jpeg"
                }}
            ]
        }]
    }

    resp = requests.post(
        "https://api.apiyi.com/v1/messages",
        headers={"Authorization": "Bearer YOUR_API_KEY"},
        json=payload,
        timeout=120
    )
    return resp.json()

这种"先校验再发送"的写法可以把 90% 的 Nano Banana Pro 报错 拦截在调用之前,避免污染 Gemini 端的失败日志。

修复 3:批量图片正确拆成多个 parts

如果你确实需要一次给 Nano Banana Pro 传多张参考图(例如做风格迁移 + 人物锁定),正确的做法是为每张图建立独立的 parts 元素,而不是把数组塞进 fileUri:

// ✅ 正确写法
const imageUrls = [
  "https://cdn.example.com/style.jpg",
  "https://cdn.example.com/person.jpg"
];

const payload = {
  model: "gemini-3-pro-image-preview",
  contents: [{
    parts: [
      { text: "把第二张图的人物画成第一张图的风格" },
      ...imageUrls.map(url => ({
        fileData: { fileUri: url, mimeType: "image/jpeg" }
      }))
    ]
  }]
};

const resp = await fetch("https://api.apiyi.com/v1/messages", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "Bearer YOUR_API_KEY"
  },
  body: JSON.stringify(payload)
});

这种写法不仅能避免 Unsupported file URI type,还能让 Gemini 正确理解多图之间的语义关系。

修复 4:不可达 URL 退回到 base64 内联

如果你拿到的 URL 是私有桶、内网地址或者临时 URL,可能在 Gemini 服务器侧根本拉不到。最稳的退路是改用 inlineData + base64:

import base64
import requests

def call_with_base64(prompt: str, local_path: str):
    with open(local_path, "rb") as f:
        b64 = base64.b64encode(f.read()).decode("utf-8")

    payload = {
        "model": "gemini-3-pro-image-preview",
        "contents": [{
            "parts": [
                {"text": prompt},
                {"inlineData": {
                    "mimeType": "image/jpeg",
                    "data": b64
                }}
            ]
        }]
    }

    return requests.post(
        "https://api.apiyi.com/v1/messages",
        headers={"Authorization": "Bearer YOUR_API_KEY"},
        json=payload
    ).json()

注意:inlineData 用的是 data 字段(纯 base64,不带 data:image/jpeg;base64, 前缀),fileData 用的是 fileUri 字段,两者互斥,不要同时填。

🎯 稳定性建议:对于 URL 来源不可控的场景(例如来自客户上传 / 第三方接口),我们建议把 图生图 默认走 base64 内联 + 通过 API易 apiyi.com 这样的中转平台调用 gemini-3-pro-image-preview,避免 Gemini 因为各种网络/权限问题间歇性拒绝外部 URL。

Nano Banana Pro 报错排查动作清单

把上面所有内容浓缩成一份"5 分钟排查"清单,客户出现 Unsupported file URI type 时直接对照执行即可。

5 分钟排查清单

步骤 动作 期望结果
1 把报错消息中 Unsupported file URI type: 后面的字面量复制出来 拿到 Gemini 实际接收到的 fileUri 值
2 检查这个值是不是包含 {{undefinednull[ 命中 → 90% 是模板未渲染或字段名错
3 用浏览器无痕窗口直接打开这个 URL 期望:能下载到一张合法 JPEG/PNG/WEBP
4 检查 URL 协议是否为 https://gs:// 不是 → 改协议或换 base64
5 检查是否是私有桶、过期签名或重定向 是 → 换公网 URL 或改 base64
6 在 API易 apiyi.com 控制台用同一个模型 + 一张已知公开图复现 复现成功 → 问题在客户端;复现失败 → 反馈给我们

只要走完这 6 步,基本上没有任何一条 Nano Banana Pro 报错 能藏住自己的根因。

Nano Banana Pro Unsupported file URI type 常见问题 FAQ

Q1:为什么报错信息里直接写出了 {{ $json.imageUrls }} 这串字面量?

因为 Gemini API 在收到请求时,把 fileUri 字段的值原样写进了报错消息——这是 Google 官方的标准行为,目的就是帮你快速定位"我到底传了什么进去"。如果你看到的字面量长得像 {{ ... }},这是 100% 的低代码工作流模板变量未渲染;如果是 undefined / null,则是字段名 typo。建议先在 API易 apiyi.com 上用一个写死的公网 URL 复现一次成功调用,再把客户端往这套成功 body 上对齐。

Q2:Nano Banana Pro / gemini-3-pro-image-preview 到底支持哪些 URL?

按 Google 官方文档,fileUri 接受 4 类 URI:File API 路径(https://generativelanguage.googleapis.com/files/...)、YouTube URL(主要用于视频理解)、公网 HTTPS URL(包括 S3 Pre-signed、Azure SAS)、GCS gs:// URI。Gemini 2.5 及更新的模型都原生支持公网 HTTPS,因此 gemini-3-pro-image-preview 不需要先把图传到 File API 再调用。

Q3:n8n 里 {{ $json.imageUrls }} 没渲染怎么办?

最常见的修复点有 3 个:第一,HTTP Request 节点的 JSON Body 必须开启表达式模式(整段 JSON 前有 = 号或左侧 fx 按钮亮起);第二,字段路径要和上一步节点的真实输出对得上,可以在 n8n 的 "Execute Node" 后查看 Output 面板确认字段名;第三,如果你用的是 sub-node,表达式默认只取第一条 item,要么改用主 node,要么先用 Item Lists 节点把数据展开。

Q4:报错里写着 undefined 该怎么修?

说明你在代码里访问了一个不存在的字段。最快的修复是在调 Gemini 之前加一道断言:assert image_url is not None and isinstance(image_url, str);然后再去上游接口的返回值中确认字段名,常见 typo 包括 imageUrls vs imageUrlimage_url vs imageUrlurl vs uri。在生产环境建议像本文 "修复 2" 那段 Python 代码一样,把"非 https/gs"的字符串直接挡在请求外。

Q5:能不能把多张图直接塞进 fileUri?

不能。fileUri 只接受单个字符串。如果要传多张图,正确做法是为每张图新建一个 { "fileData": { "fileUri": "...", "mimeType": "..." } } 元素,然后把它们都放到同一个 parts 数组里。这样 Gemini 才能正确识别多图之间的语义关系。

Q6:私有桶或者临时签名 URL 实在不能公开怎么办?

最稳的兜底方案是改用 inlineData + base64:把图片在你这边读出来,base64 编码后直接放进请求 body。这样完全不需要 Gemini 服务器去拉外部资源,也就避开了所有"鉴权失败 / 签名过期 / MIME 不匹配"的坑。代价是请求体会变大,适合单图小尺寸场景。如果你做的是高并发图生图,仍然建议把图先上传到一个公网可达的 CDN 上,再通过 API易 apiyi.com 调用 gemini-3-pro-image-preview,这样既避免 base64 体积膨胀,也方便平台层统一做缓存与重试。

nano-banana-pro-unsupported-file-uri-type-error-fix 图示

总结:Nano Banana Pro 报错修复后的最佳实践

回到客户那条具体的 Nano Banana Pro 报错:Unsupported file URI type: {{ $json.imageUrls }},我们已经可以非常确定地告诉他——这不是 Gemini 的问题,而是 n8n / 低代码工作流没有把模板变量替换成真实 URL,导致整段 {{ ... }} 字面量被原样发到了 Gemini API。修复方法在本文 "修复 1" 里已经给出,只要让 HTTP Request 节点的 JSON Body 开启表达式模式、确认上一步节点真的输出了 imageUrls 字段,这条报错就会立刻消失。

在更广义的层面,Unsupported file URI type 这条报错暴露出来的是一个非常普遍的问题:很多团队在调用图像 API 时缺少"输入校验"这一层,导致 Gemini 端拒绝请求时,根本看不出来到底是模型问题、网络问题还是参数问题。本文给出的 5 分钟排查清单 + Python 校验代码 + n8n 表达式写法,可以直接拿来作为团队的标准应对动作。

🎯 最终建议:如果你正在为客户搭建基于 gemini-3-pro-image-preview 的图生图工作流,我们建议把所有 Nano Banana Pro 调用统一收敛到 API易 apiyi.com 这种中转平台,既能在控制台快速复现 + diff 失败请求,也能在 Google 自身故障时无缝切换到 Nano Banana 2 / Seedream 等同档位模型,让 Unsupported file URI type 这类参数错误第一时间被定位与修复。


作者:APIYI Team | 关注 AI 大模型落地与稳定性工程,更多 Gemini 与图像 API 实战排查请访问 API易 apiyi.com。

类似文章