# Nano Banana Pro "Unsupported File URI Type"? Fix the Gemini File Route

> For "Unsupported file URI type," check the exact image value your app sent and the endpoint that rejected it. Native Gemini can accept supported HTTPS URLs; local paths, unresolved templates and base64 data URLs need a different payload. Verify the repair by getting an edited image from the same Pro request.

- URL: https://blog.laozhang.ai/en/posts/nano-banana-pro-unsupported-file-uri-type
- Published: 2026-04-09
- Updated: 2026-10-07
- Author: LaoZhang AI Team (https://blog.laozhang.ai/en/about)
- Topic: Troubleshooting
- Tags: Nano Banana Pro, Gemini API, Files API, image_url, API Troubleshooting

---
If Nano Banana Pro returns **"Unsupported file URI type"** or **"Invalid or unsupported file uri,"** inspect the image reference in the final outgoing request before changing the prompt. A workflow expression such as `{{ $json.imageUrls }}`, an array, a local path or a `data:` URL can end up where the API expects one URI string.

**Native Gemini can accept supported public HTTPS and presigned URLs.** Google's [current file-input guide](https://ai.google.dev/gemini-api/docs/generate-content/file-input-methods), updated October 1, 2026, documents this alongside inline bytes, uploaded files and registered Google Cloud Storage objects. Advice that every native HTTPS image must be uploaded first is outdated. The URL still has to satisfy the selected model's input support, retrieval rules, access conditions and size limits.

For a native Nano Banana Pro image-editing request, keep the `generateContent` endpoint and the intended Pro model, currently `gemini-3-pro-image` in [Google's image-generation guide](https://ai.google.dev/gemini-api/docs/generate-content/image-generation). Send an image as either a supported scalar `fileData.fileUri` or raw base64 bytes in `inlineData`. Then check that the response contains a final image and that it performs the requested edit. A text description of the input is not proof that image editing works.

## 30-Second Route Board

![The actual URI scheme and value shape choose supported URL input, inline bytes, upload, or route-specific registration.](https://blog.laozhang.ai/posts/en/nano-banana-pro-unsupported-file-uri-type/img/uri-routes.webp)

First identify the host, model, method and image field actually sent by your application. An SDK's input object or a workflow's preview is useful, but it may differ from the serialized request.

| Final image input | What to check | Smallest useful repair |
|---|---|---|
| `{{ $json.imageUrls }}` or similar template text | Did the workflow evaluate the expression before sending it? | Fix expression mode and the source field; confirm the outgoing value is the intended string. |
| An array or a string such as `["https://…"]` | Does one file URI field contain multiple values? | Create one image part per image, each with one URI string. |
| Public or presigned HTTPS URL | Does this model and endpoint support URL input? Can Gemini retrieve the image before the link expires? | Keep a supported URL, correct its access/MIME conditions, or use approved local bytes to isolate retrieval. |
| `data:image/png;base64,…` in native `fileUri` | Was a compatibility-style data URL placed in a native URI field? | Put raw base64 in native `inlineData.data`, with `mimeType`, and remove the data-URL prefix. |
| `/tmp/input.png`, `file://…` or Android `content://…` | Is this only accessible to the device running your app? | Read the image into inline bytes or upload it and use the returned URI. |
| A Gemini upload URI that worked earlier | Is the File still available and `ACTIVE`? | Check its state and expiry; upload again if the resource expired. |
| `gs://bucket/object.png` | Are you using Gemini registration or a Vertex-specific request? | Follow the actual route's storage and authorization contract; on Gemini, use the supported registration flow. |

The field names and accepted data shapes come from Google's [native `generateContent` reference](https://ai.google.dev/api/generate-content). One `Part` holds one data kind: text and image belong in separate parts. A valid PNG does not fix an invalid URI, and a syntactically valid URI does not guarantee the server can retrieve its image.

## Inspect the Value That Reached the API

Before retrying, inspect the final image part without logging the full key, signed query string or private image bytes. You need to know the field name, whether the value is a string, its scheme, and whether it still contains template syntax. For a signed URL, redact the query parameters in diagnostics.

[APIYI's April 8 workflow report](https://help.apiyi.com/en/nano-banana-pro-unsupported-file-uri-type-error-fix-en.html) describes the literal string `{{ $json.imageUrls }}` reaching an image request. That is a useful clue when your error includes the same expression. It does not establish that every occurrence has a template-related cause or that a particular workflow recipe fixes every provider.

Check three places in the pipeline:

1. **The source field:** confirm the current item actually contains the image value. `imageUrl` and `imageUrls` are different property names.
2. **The transformation:** confirm a template was evaluated and an array was split into separate media parts, rather than converted into one string.
3. **The outgoing JSON:** confirm the actual serializer produced the field and type the endpoint expects.

Missing values deserve their own check. In JavaScript, `JSON.stringify({fileUri: undefined})` omits that property; explicit `String(undefined)` produces the string `"undefined"`. Neither is a usable image reference, but they are different outgoing requests. Diagnose what was sent instead of assuming a variable name proves its value.

If the outgoing part already has the correct shape, move on to image access, MIME, resource lifetime and wrapper behavior. Different mistakes can produce different validation messages; the error text alone does not identify a universal cause.

## If You Are Using Native Gemini `file_data`

The native route is:

```text
POST https://generativelanguage.googleapis.com/v1beta/models/gemini-3-pro-image:generateContent
```

The JSON below uses the camel-case fields in Google's native schema: `fileData`, `fileUri`, `inlineData` and `mimeType`. Some REST examples use snake case, and Python SDK objects use their own documented names. Keep the chosen serializer's shape consistent; do not insert OpenAI-style `image_url` message items into native `contents[].parts[]`.

### Send a supported HTTPS image URL

For an image URL your application is permitted to share with Gemini, this is a native editing payload. Replace the illustrative URL with your actual supported image URL before sending it:

```json
{
  "contents": [
    {
      "role": "user",
      "parts": [
        {"text": "Change the background to light blue. Keep the main subject unchanged."},
        {
          "fileData": {
            "mimeType": "image/png",
            "fileUri": "https://media.example.com/input.png"
          }
        }
      ]
    }
  ],
  "generationConfig": {"responseModalities": ["TEXT", "IMAGE"]}
}
```

Google retrieves the URL during processing. The image must be accessible through that request without your browser's session cookies, and a signed URL must remain valid long enough to be fetched. Confirm it points to image content rather than a login page, an HTML preview or an expired-link response. Set the MIME type to the actual image type, not a guess based solely on a filename.

The [file-input guide](https://ai.google.dev/gemini-api/docs/generate-content/file-input-methods) supports public HTTPS and presigned S3/Azure URLs on applicable models, while excluding the Gemini 2.0 family from this method. It does not promise that every gateway, wrapper or image format shares the same support. A URL that opens in your browser is therefore a useful check, not a complete acceptance test.

For private images, use your approved scoped, short-lived access method or local bytes. Making an entire bucket public is unnecessary. If retrieval returns `URL_RETRIEVAL_STATUS_UNSAFE`, stop treating that as an ordinary expiry problem: it is a retrieval-policy rejection, and removing protections is not the repair.

### Use local bytes to isolate the URL problem

If you have an authorized local copy of the image, inline input removes remote retrieval from the test. Native `inlineData.data` contains **base64 of the raw image bytes, without `data:image/…;base64,`**. This differs from a compatibility `image_url` data URL. Google's [image-generation guide](https://ai.google.dev/gemini-api/docs/generate-content/image-generation) documents native image editing with image input and image output.

Save this as `prepare_edit.py`. It reads a PNG you supply and writes a complete request body; it makes no API call:

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

if len(sys.argv) != 2:
    raise SystemExit("Usage: python3 prepare_edit.py input.png")

image = Path(sys.argv[1]).read_bytes()
if not image.startswith(b"\x89PNG\r\n\x1a\n"):
    raise SystemExit("This example expects a PNG; use the actual MIME for another format.")

payload = {
    "contents": [{
        "role": "user",
        "parts": [
            {"text": "Change the background to light blue. Keep the main subject unchanged."},
            {"inlineData": {
                "mimeType": "image/png",
                "data": base64.b64encode(image).decode("ascii")
            }}
        ]
    }],
    "generationConfig": {"responseModalities": ["TEXT", "IMAGE"]}
}
Path("request.json").write_text(json.dumps(payload), encoding="utf-8")
```

Run the preparation step with a small PNG you can recognize. Then, from a terminal where your own authorized `GEMINI_API_KEY` is already configured, submit the body to the same native Pro endpoint:

```bash
python3 prepare_edit.py input.png
curl --silent --show-error --fail-with-body \
  'https://generativelanguage.googleapis.com/v1beta/models/gemini-3-pro-image:generateContent' \
  -H "x-goog-api-key: ${GEMINI_API_KEY}" \
  -H 'Content-Type: application/json' \
  --data-binary @request.json \
  --output response.json
```

This generation request can incur charges. The examples here were checked offline for payload construction and decoding, not submitted as a live editing test. For the URL variant, save the corrected URL payload as `request.json` and use the same submission command.

If inline bytes work but the supported URL variant fails on the same endpoint and model, investigate retrieval or the wrapper's handling of URLs. If both fail with malformed-input errors, examine the native payload, MIME and original image bytes first. Keep the comparison on the same Pro model so a successful image-captioning request does not conceal a broken editing route.

### Upload an image and reuse the returned File URI

Upload is useful when you want to reuse a file without embedding its bytes in every request. With an already configured Google Gen AI SDK `client`, the upload step is:

```python
uploaded = client.files.upload(file="input.png")
print(uploaded.uri, uploaded.mime_type)
```

This is an upload fragment, not a complete client-setup script. Use the returned `uri` as the native payload's `fileData.fileUri` and its actual MIME as `mimeType`. Do not substitute `uploaded.name`, a guessed `files/...` path or the original local filename.

Check the File metadata before inference. `ACTIVE` means ready; `PROCESSING` means it is not ready yet; `FAILED` means inspect the file error and stop blindly retrying. If processing is relevant, use bounded polling through `files.get`, with failure and timeout handling. Standard uploaded files are retained for **48 hours**, so old cached references need an expiry check. See the [Files API reference](https://ai.google.dev/api/files) and the [file-input method limits](https://ai.google.dev/gemini-api/docs/generate-content/file-input-methods).

## If Your Input Is a GCS Object, Public URL, or Vertex Path

The correct method depends on which service owns the request. Direct HTTPS input, a Gemini upload and a registered GCS object are distinct methods; a storage object's existence does not make every reference to it interchangeable.

For supported GCS registration on the Gemini Developer API, the registration endpoint is `POST https://generativelanguage.googleapis.com/v1beta/files:register`. Its request takes a `uris` array of GCS object strings; its response returns File resources. Use a returned File's URI for generation. This registration array does **not** mean `fileData.fileUri` itself can be an array.

Registration requires the documented caller OAuth authorization, enabled API/service identity, and appropriate caller and Gemini service-agent access to the objects. Google's guide describes bucket-scoped Storage Object Viewer access for the service agent. **An API key alone is not sufficient for registration.** Follow the [GCS registration prerequisites](https://ai.google.dev/gemini-api/docs/generate-content/file-input-methods) and [register API reference](https://ai.google.dev/api/files), rather than changing bucket visibility to fix a URI error.

Registered objects are fetched when used and one registration provides access for up to **30 days**. That is different from the standard upload's 48-hour storage period. Registration also fails as a whole if any requested object cannot be registered, so inspect the registration response before building the editing request.

If your application actually calls Vertex AI, retain its project, location, publisher and identity contract. Do not silently move a Gemini Developer API request to Vertex because both products use Google models. A [March 2025 forum report](https://discuss.ai.google.dev/t/400-invalid-or-unsupported-file-uri/73951) concerned Gemini 2.0 and GCS/API-key versus Vertex authorization; it does not override the current HTTPS-input and registration documentation.

## If You Are Using OpenAI-Compatible `image_url`

Gemini's own compatibility endpoint uses `/v1beta/openai/` and OpenAI-style message content. Its [image-understanding documentation](https://ai.google.dev/gemini-api/docs/openai) supports an `image_url` item whose `url` can be a base64 data URL, such as `data:image/png;base64,…`.

That shape belongs to the documented compatibility operation. It does not make a data URL valid in native `fileData.fileUri`, and an image-understanding example does not establish that your compatibility chat-completions request can produce a Nano Banana Pro edited image. Confirm the provider's supported model, editing action and output format before changing fields.

If compatibility image input fails, check that the data URL was preserved and that the client did not rewrite it into a native URI field. If your intended operation is the native Pro edit demonstrated above, use the complete native payload and endpoint together. Do not combine a native file part with an OpenAI message structure and expect either API to infer your intention.

## Verify the Fix and Catch the Remaining Edge Cases

![Checking the result, file lifetime and wrapper behavior after correcting the image input](https://blog.laozhang.ai/posts/en/nano-banana-pro-unsupported-file-uri-type/img/verify-flow.webp)

Verification means getting the intended image through the same route that failed. HTTP 200, a successful upload or a response describing the source image is insufficient.

For the native REST response saved above, this decoder extracts non-thought image parts. Save it as `save_edit.py` and run `python3 save_edit.py`:

```python
import base64
import json
from pathlib import Path

response = json.loads(Path("response.json").read_text(encoding="utf-8"))
if "error" in response:
    raise SystemExit("The API returned an error; inspect its status and message safely.")

extensions = {"image/png": "png", "image/jpeg": "jpg", "image/webp": "webp"}
count = 0
for candidate in response.get("candidates", []):
    for part in candidate.get("content", {}).get("parts", []):
        if part.get("thought"):
            continue
        image = part.get("inlineData") or part.get("inline_data")
        if not image:
            continue
        mime = image.get("mimeType") or image.get("mime_type", "")
        if mime not in extensions or not image.get("data"):
            continue
        raw = base64.b64decode(image["data"], validate=True)
        if not raw:
            raise SystemExit("The image part decoded to empty bytes.")
        count += 1
        Path(f"edited-{count}.{extensions[mime]}").write_bytes(raw)
if count == 0:
    raise SystemExit("No final image found; inspect finishReason and promptFeedback.")
print(f"Saved {count} image(s). Open them and verify the requested edit.")
```

Open the saved image and check the requested background change and retained subject. If no image was returned, read the candidate's `finishReason` and the response's `promptFeedback`; do not label a text-only result as a repaired editing workflow. For HTTP errors or blocked/empty image results beyond file routing, continue with [Gemini image error codes and retry rules](https://blog.laozhang.ai/en/posts/gemini-image-common-errors-fix), which distinguishes native status responses from other API shapes.

If the reference remains rejected, compare the failing application's final request with the direct native payload:

- **Wrapper conversion:** an SDK may download a URL locally and submit bytes, while a gateway may pass the URL through. Those are different input paths even when your application code starts with the same URL.
- **MIME and contents:** confirm the bytes actually match the declared image type. An HTML response labeled `image/png` is not a PNG.
- **Lifetime:** distinguish a signed input URL's expiry, an uploaded File's expiry and a registered object's access period.
- **Provider limits:** Google's generic file-method limits are not a universal Nano Banana Pro or gateway allowance. The [Comfy Router Pro documentation](https://docs.comfy.org/ja/development/comfy-router/models/google/nano-banana-pro/code), for example, specifies 20 MB inline input and 24-hour generated-image signed URLs on its own route. Those are separate from Google's upload retention and registration periods.

Historical [Vercel AI issue 10692](https://github.com/vercel/ai/issues/10692) and [issue 10349](https://github.com/vercel/ai/issues/10349) describe URL handling differences in 2025 wrapper versions. They justify checking your actual adapter and wire payload; their closed status does not prove a current 2026 bug, a universal fix or a need to downgrade.

Once the symptom changes to model access, authorization, quota or another error, follow that error's specific instructions. Repeatedly rewriting the image URI will not repair an unrelated 403, model 404 or quota 429.

## FAQ

### Can I use a public HTTPS URL directly in native Gemini?

Yes, on a supported model and request route, subject to retrieval, permissions, MIME and size conditions. Google's [current file-input guide](https://ai.google.dev/gemini-api/docs/generate-content/file-input-methods) documents public HTTPS and presigned input URLs; it excludes Gemini 2.0 from this method. Uploading is an alternative, not a mandatory step for every HTTPS image.

### Does `data:image/…;base64,…` belong anywhere in Gemini?

Yes, in the documented compatibility `image_url` operation. For native image input, put raw base64 in `inlineData.data` with the correct `mimeType`, without that prefix. See the [compatibility guide](https://ai.google.dev/gemini-api/docs/openai) and [native API schema](https://ai.google.dev/api/generate-content). Neither input shape by itself proves Pro editing output.

### Can I pass several URLs in one `fileUri`?

No. The [native schema](https://ai.google.dev/api/generate-content) defines `fileUri` as a string. Add a separate media part for each intended image, within the selected model's limits. A JSON array and a stringified array are both different from one valid URI.

### Do local files have to be uploaded first?

No. Read their bytes into native `inlineData`, or upload them and reuse the returned File URI. Sending `/tmp/input.png`, `file://…` or a device-only `content://…` as the remote reference does not give Gemini access to the file on your device.

### Does every reusable reference expire after 48 hours?

No. Standard Gemini uploads last 48 hours; registered GCS access can last up to 30 days per registration; signed URLs follow their own expiry. Check the metadata and the provider's contract rather than imposing one lifetime on every method. Google's [file-input guide](https://ai.google.dev/gemini-api/docs/generate-content/file-input-methods) distinguishes these methods.

## Sources

External pages this guide links to, in the order they appear. Last updated 2026-10-07.

- [current file-input guide](https://ai.google.dev/gemini-api/docs/generate-content/file-input-methods) (ai.google.dev)
- [Google's image-generation guide](https://ai.google.dev/gemini-api/docs/generate-content/image-generation) (ai.google.dev)
- [native generateContent reference](https://ai.google.dev/api/generate-content) (ai.google.dev)
- [APIYI's April 8 workflow report](https://help.apiyi.com/en/nano-banana-pro-unsupported-file-uri-type-error-fix-en.html) (help.apiyi.com)
- [Files API reference](https://ai.google.dev/api/files) (ai.google.dev)
- [March 2025 forum report](https://discuss.ai.google.dev/t/400-invalid-or-unsupported-file-uri/73951) (discuss.ai.google.dev)
- [image-understanding documentation](https://ai.google.dev/gemini-api/docs/openai) (ai.google.dev)
- [Comfy Router Pro documentation](https://docs.comfy.org/ja/development/comfy-router/models/google/nano-banana-pro/code) (docs.comfy.org)
- [Vercel AI issue 10692](https://github.com/vercel/ai/issues/10692) (github.com)
- [issue 10349](https://github.com/vercel/ai/issues/10349) (github.com)
