Skip to content

Issue with Gemini 2.5 models #9

@fredlef

Description

@fredlef

I am consistently getting this error with gemini 2.5. I did a lot of troubleshooting on nodes I created and finally tried just a minimal node with the code from the model documentation (see attached). This is the error -

got prompt
Executing prompt: 4e05a1af-7048-4cae-aaaf-da7063cc36ac
[WaveSpeed] Model: google/gemini-2.5-flash-image/edit
[WaveSpeed] Payload keys: ['enable_base64_output', 'prompt', 'aspect_ratio', 'images']
[WaveSpeed] Request ID: 2351b27d525946f48e9a63766681c496
[WaveSpeed] Status: created (0s)
[WaveSpeed] Status: created (11s)
[WaveSpeed] Status: created (21s)
[WaveSpeed] Status: created (32s)
[WaveSpeed] Status: failed (42s)
!!! Exception during processing !!! Task failed: Request failed. Please check your input parameters and try again.
Traceback (most recent call last):
File "C:\Users\fredlef\Documents\comfyui312\ComfyUI\execution.py", line 516, in execute
output_data, output_ui, has_subgraph, has_pending_tasks = await get_output_data(prompt_id, unique_id, obj, input_data_all, execution_block_cb=execution_block_cb, pre_execute_cb=pre_execute_cb, v3_data=v3_data)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\fredlef\Documents\comfyui312\ComfyUI\execution.py", line 330, in get_output_data
return_values = await _async_map_node_over_list(prompt_id, unique_id, obj, input_data_all, obj.FUNCTION, allow_interrupt=True, execution_block_cb=execution_block_cb, pre_execute_cb=pre_execute_cb, v3_data=v3_data)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\fredlef\Documents\comfyui312\ComfyUI\execution.py", line 304, in _async_map_node_over_list
await process_inputs(input_dict, i)
File "C:\Users\fredlef\Documents\comfyui312\ComfyUI\execution.py", line 292, in process_inputs
result = f(**inputs)
^^^^^^^^^^^
File "C:\Users\fredlef\Documents\comfyui312\ComfyUI\custom_nodes\Comfyui_FSL_Nodes\FSLWaveSpeedMinimal.py", line 162, in generate
output = poll_for_result(api_key, request_id)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\fredlef\Documents\comfyui312\ComfyUI\custom_nodes\Comfyui_FSL_Nodes\FSLWaveSpeedMinimal.py", line 74, in poll_for_result
raise RuntimeError(f"Task failed: {error}")
RuntimeError: Task failed: Request failed. Please check your input parameters and try again.

Prompt executed in 44.26 seconds
+---------+---------------------+----------+-----------+
| Node ID | Type | Time (s) | VRAM (GB) |
+---------+---------------------+----------+-----------+
| #22 | FSLWaveSpeedMinimal | 44.23 | 0.00 |
| TOTAL | - | 44.61 | - |

Thanks,
Fred

"""
FSL WaveSpeed Minimal - Based on WaveSpeed API documentation
Starting minimal and building up carefully
"""
import os
import time
import base64
import requests
import random
import numpy as np
from PIL import Image
from io import BytesIO
import torch

NODE_CATEGORY = "FSL/WaveSpeed"
WAVESPEED_API_BASE = "https://api.wavespeed.ai/api/v3"

Minimal model list - known working

GEMINI_MODELS = [
"google/gemini-3-pro-image/edit",
"google/gemini-2.5-flash-image/edit",
]

ASPECT_CHOICES = ("1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3")

==============================================================================

HELPERS

==============================================================================

def tensor2pil(image):
if image is None:
return None
if len(image.shape) == 4:
image = image[0]
arr = np.clip(255.0 * image.cpu().numpy(), 0, 255).astype(np.uint8)
return Image.fromarray(arr)

def pil2tensor(image):
arr = np.array(image).astype(np.float32) / 255.0
return torch.from_numpy(arr).unsqueeze(0)

def image_to_base64(image_tensor):
"""Convert single image tensor to base64 string with data URI prefix."""
if image_tensor is None:
return None
pil_img = tensor2pil(image_tensor).convert("RGB")
buf = BytesIO()
pil_img.save(buf, format="PNG")
return "data:image/png;base64," + base64.b64encode(buf.getvalue()).decode("utf-8")

def poll_for_result(api_key, request_id, timeout=300):
"""Poll WaveSpeed API for result - based on their documentation."""
url = f"{WAVESPEED_API_BASE}/predictions/{request_id}/result"
headers = {"Authorization": f"Bearer {api_key}"}
start = time.time()

while time.time() - start < timeout:
    response = requests.get(url, headers=headers, timeout=30)
    elapsed = int(time.time() - start)
    
    if response.status_code == 200:
        result = response.json().get("data", {})
        status = result.get("status", "").lower()
        
        print(f"[WaveSpeed] Status: {status} ({elapsed}s)")
        
        if status == "completed":
            outputs = result.get("outputs", [])
            if outputs:
                return outputs[0]  # Return first output URL or base64
            raise RuntimeError("Task completed but no outputs returned")
        elif status == "failed":
            error = result.get("error", "Unknown error")
            raise RuntimeError(f"Task failed: {error}")
    else:
        print(f"[WaveSpeed] HTTP {response.status_code} ({elapsed}s)")
    
    time.sleep(10)

raise RuntimeError(f"Timeout after {timeout}s")

==============================================================================

NODE

==============================================================================

class FSLWaveSpeedMinimal:
"""Minimal WaveSpeed node - based directly on API documentation."""

@classmethod
def INPUT_TYPES(s):
    return {
        "required": {
            "prompt": ("STRING", {"multiline": True, "default": ""}),
            "model": (GEMINI_MODELS, {"default": "google/gemini-3-pro-image/edit"}),
            "aspect_ratio": (ASPECT_CHOICES, {"default": "1:1"}),
            "api_key": ("STRING", {"default": ""}),
        },
        "optional": {
            "image": ("IMAGE",),
            "seed": ("INT", {"default": -1, "min": -1, "max": 2147483647}),
        }
    }

RETURN_TYPES = ("IMAGE", "STRING")
RETURN_NAMES = ("image", "info")
FUNCTION = "generate"
CATEGORY = NODE_CATEGORY

def generate(self, prompt, model, aspect_ratio, api_key, image=None, seed=-1):
    # Resolve API key
    if not api_key:
        api_key = os.environ.get("WAVESPEED_API_KEY", "")
    if not api_key:
        raise RuntimeError("No API key provided")
    
    # Handle seed
    if seed == -1:
        seed = random.randint(0, 2147483647)
    
    # Build minimal payload - start with what their docs show works
    payload = {
        "enable_base64_output": True,
    }
    
    # Add prompt if provided
    if prompt.strip():
        payload["prompt"] = prompt.strip()
    
    # Add aspect ratio
    payload["aspect_ratio"] = aspect_ratio
    
    # Add image if provided
    if image is not None:
        b64 = image_to_base64(image)
        if b64:
            payload["images"] = [b64]
    
    # Debug output
    print(f"[WaveSpeed] Model: {model}")
    print(f"[WaveSpeed] Payload keys: {list(payload.keys())}")
    
    # Make request
    url = f"{WAVESPEED_API_BASE}/{model}"
    headers = {
        "Content-Type": "application/json",
        "Authorization": f"Bearer {api_key}",
    }
    
    response = requests.post(url, json=payload, headers=headers, timeout=60)
    
    if response.status_code != 200:
        raise RuntimeError(f"API Error ({response.status_code}): {response.text}")
    
    result = response.json()
    if "data" not in result:
        raise RuntimeError(f"Unexpected response: {result}")
    
    request_id = result["data"]["id"]
    print(f"[WaveSpeed] Request ID: {request_id}")
    
    # Poll for result
    output = poll_for_result(api_key, request_id)
    
    # Decode result
    if output.startswith("data:") or output.startswith("http"):
        if "base64," in output:
            img_data = output.split("base64,")[1]
            pil_img = Image.open(BytesIO(base64.b64decode(img_data))).convert("RGB")
        else:
            # It's a URL - fetch it
            img_response = requests.get(output, timeout=60)
            pil_img = Image.open(BytesIO(img_response.content)).convert("RGB")
    else:
        # Assume raw base64
        pil_img = Image.open(BytesIO(base64.b64decode(output))).convert("RGB")
    
    info = f"model={model}, aspect={aspect_ratio}, seed={seed}, size={pil_img.width}x{pil_img.height}"
    
    return (pil2tensor(pil_img), info)

==============================================================================

REGISTRATION

==============================================================================

NODE_CLASS_MAPPINGS = {
"FSLWaveSpeedMinimal": FSLWaveSpeedMinimal,
}

NODE_DISPLAY_NAME_MAPPINGS = {
"FSLWaveSpeedMinimal": "FSL WaveSpeed Minimal (Test)",
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions