# Nano Banana 2: qué hacer ante el error 503 «Model is overloaded»

> Si Nano Banana 2 devuelve un 503 «Model is overloaded», reintenta con esperas variables y un límite total. Cuando ese límite se agota, conserva la tarea para después; una respuesta 200 solo cuenta como éxito si contiene una imagen utilizable.

- URL: https://blog.laozhang.ai/es/posts/nano-banana-2-503-overloaded-fix
- Published: 2026-03-09
- Updated: 2026-10-07
- Author: LaoZhang AI Team (https://blog.laozhang.ai/es/about)
- Topic: Resolución de problemas
- Tags: Nano Banana 2, Error 503, Gemini API, Reintentos

---
**Si Nano Banana 2 devuelve un 503 «Model is overloaded», deja de reenviar la solicitud en un bucle inmediato.** Confirma el estado HTTP, conserva el detalle del error y aplica reintentos con retroceso exponencial, variación aleatoria y límites de intentos y tiempo. Si el servicio sigue sin responder, pausa la tarea o déjala en una cola. Al recuperarse, comprueba que la respuesta contiene una imagen que se puede abrir: recibir texto o un HTTP 200 no basta.

La [ficha actual de Nano Banana 2](https://ai.google.dev/gemini-api/docs/models/gemini-3.1-flash-image) identifica el modelo como `gemini-3.1-flash-image`, con entrada de texto e imágenes y salida de texto e imágenes. El ejemplo de abajo sirve para generar una imagen y para editar una imagen de entrada mediante la API nativa de Gemini. No depende de que un modelo de texto pueda sustituir esa salida.

## Comprueba qué ha fallado antes de reintentar

Un [503 significa que el servicio no puede atender la solicitud en ese momento](https://www.rfc-editor.org/rfc/rfc9110.html#section-15.6.4), por ejemplo por sobrecarga temporal o mantenimiento. No demuestra por sí solo que Nano Banana 2 esté caído para todos los usuarios. Si usas un intermediario, el 503 puede proceder de ese intermediario: necesitas su respuesta y, cuando esté disponible, el error del servicio de origen.

Guarda la fecha y hora, el endpoint, el modelo solicitado, el código HTTP, el cuerpo del error, la cabecera `Retry-After`, la duración y el identificador de solicitud disponible. Excluye claves y datos sensibles del registro. Con esos datos puedes distinguir una interrupción del servicio de un problema de cuota, de una petición incorrecta o de una respuesta sin imagen.

![Cada resultado de la solicitud de imagen requiere una acción distinta: 503, 429, error de entrada, imagen ausente o timeout](https://blog.laozhang.ai/posts/es/nano-banana-2-503-overloaded-fix/img/error-diagnosis-flowchart.webp)

| Resultado observado | Primera acción | ¿Reenviar automáticamente? |
| --- | --- | --- |
| 503 confirmado en la respuesta HTTP o en el error tipado del SDK | Esperar y volver a intentarlo dentro del presupuesto | Sí, con un límite y después de comprobar la política de reintentos de cada capa |
| 429 | Leer el detalle y comprobar qué límite o cuota se ha agotado | Solo si es una restricción temporal; no insistir ante una cuota agotada sin posibilidad de recuperación inmediata |
| 400, 402 o 403 | Corregir la petición, revisar el saldo aplicable o resolver el acceso, según el error | No con la misma petición sin cambios |
| 200 sin una imagen utilizable | Revisar las partes de la respuesta, el motivo de finalización y la información de bloqueo | No tratarlo como un 503 ni repetirlo a ciegas |
| Tiempo de espera agotado o conexión interrumpida sin respuesta concluyente | Conservar la tarea con resultado desconocido y revisar los registros | No asumir que la generación no llegó a ejecutarse |

La [guía de resolución de problemas de Google](https://ai.google.dev/gemini-api/docs/troubleshooting) recomienda retroceso exponencial y variación aleatoria para fallos transitorios. La distinción importa: esperar puede ayudar ante una restricción temporal, pero no corrige un campo inválido ni garantiza que una cuota diaria se restablezca dentro de tu sesión.

Si trabajas con el SDK Python `google-genai`, clasifica el error mediante el **entero `APIError.code`**, no buscando «503» dentro de una cadena. La [referencia de errores de Interactions](https://ai.google.dev/gemini-api/docs/api-errors) describe otro protocolo, con códigos de texto como `service_unavailable`; no traslades ese formato a `generateContent`.

## Código Python: generar o editar una imagen con reintentos limitados

El siguiente núcleo usa el SDK actual `google-genai` y Pillow para comprobar que los bytes recibidos se pueden decodificar como imagen. Requiere Python 3.11 o posterior, ambos paquetes disponibles en tu aplicación, una clave ya autorizada y un cliente configurado para la API de Gemini. El SDK utiliza su protocolo nativo `generateContent`; no es un ejemplo de Vertex AI ni de Interactions.

**La aplicación controla los reintentos.** Configura el SDK con `HttpRetryOptions(attempts=1)` y comprueba que tu proxy tampoco reintenta por su cuenta. Cinco intentos en la aplicación y cinco en otra capa pueden multiplicarse hasta veinticinco envíos.

Hay una discrepancia que conviene resolver explícitamente: la guía de Google describe cuatro reintentos automáticos, mientras que el [código de la rama `main` del SDK consultado el 6 de octubre](https://github.com/googleapis/python-genai/blob/main/google/genai/_api_client.py) usa un solo intento cuando `retry_options` es `None`. Esa rama no identifica necesariamente tu versión instalada. Los [tipos del SDK](https://github.com/googleapis/python-genai/blob/main/google/genai/types.py) indican además que `attempts` incluye el envío inicial y que `HttpOptions.timeout` se expresa en **milisegundos**.

```python
import asyncio
import io
import random
import time
from email.utils import parsedate_to_datetime
from pathlib import Path

from google import genai
from google.genai import errors, types
from PIL import Image


def retry_after_seconds(error, wall_clock=time.time):
    response = getattr(error, "response", None)
    headers = getattr(response, "headers", {}) or {}
    value = headers.get("Retry-After") or headers.get("retry-after")
    if not value:
        return None
    value = str(value).strip()
    if value.isdigit():
        return float(value)
    try:
        date = parsedate_to_datetime(value)
        if date.tzinfo is None:
            return None
        return max(0.0, date.timestamp() - wall_clock())
    except (ValueError, TypeError, OverflowError):
        return None


def checked_images(response):
    images = []
    for candidate in response.candidates or []:
        content = candidate.content
        for part in (content.parts or []) if content else []:
            data = part.inline_data
            if part.thought or not data:
                continue
            if not data.mime_type or not data.mime_type.startswith("image/"):
                continue
            raw = data.data
            if not isinstance(raw, bytes) or not raw:
                continue
            try:
                with Image.open(io.BytesIO(raw)) as image:
                    image.load()
                    images.append((raw, image.format))
            except (OSError, ValueError):
                continue
    return images


async def generate_bounded(
    client, prompt, input_image=None, *, attempts=4, budget=60.0,
    per_attempt=20.0, clock=time.monotonic, sleep=asyncio.sleep,
    uniform=random.uniform,
):
    if attempts < 1 or budget <= 0 or per_attempt <= 0:
        raise ValueError("Los límites deben ser positivos")
    deadline = clock() + budget
    parts = [types.Part.from_text(text=prompt)]
    if input_image is not None:
        raw, mime_type = input_image
        parts.append(types.Part.from_bytes(data=raw, mime_type=mime_type))
    contents = [types.Content(role="user", parts=parts)]
    last_error = None

    for attempt in range(1, attempts + 1):
        remaining = deadline - clock()
        if remaining <= 0:
            break
        timeout = min(per_attempt, remaining)
        try:
            async with asyncio.timeout(timeout):
                response = await client.aio.models.generate_content(
                    model="gemini-3.1-flash-image",
                    contents=contents,
                    config=types.GenerateContentConfig(
                        response_modalities=["TEXT", "IMAGE"],
                        http_options=types.HttpOptions(
                            timeout=max(1, int(timeout * 1000)),
                            retry_options=types.HttpRetryOptions(attempts=1),
                        ),
                    ),
                )
        except errors.APIError as error:
            last_error = {"code": error.code, "status": error.status,
                          "message": error.message}
            if error.code != 503:
                return {"state": "review_error", "error": last_error}
            hint = retry_after_seconds(error)
            if attempt == attempts:
                return {"state": "deferred", "error": last_error,
                        "retry_after_seconds": hint}
            backoff = uniform(0.0, min(8.0, 2.0 ** (attempt - 1)))
            delay = max(backoff, hint if hint is not None else 0.0)
            if delay >= deadline - clock():
                return {"state": "deferred", "error": last_error,
                        "retry_after_seconds": hint}
            await sleep(delay)
            continue
        except (TimeoutError, OSError) as error:
            return {"state": "unknown", "reason": type(error).__name__}
        except Exception as error:
            # Error no clasificado: no repetir una generación por defecto.
            return {"state": "review_error", "reason": type(error).__name__}

        images = checked_images(response)
        if images:
            return {"state": "completed", "images": images}
        return {"state": "no_image", "response": response}

    return {"state": "deferred", "error": last_error}


async def save_generation(api_key, prompt, input_image=None):
    client = genai.Client(
        api_key=api_key,
        http_options=types.HttpOptions(
            retry_options=types.HttpRetryOptions(attempts=1)
        ),
    )
    try:
        result = await generate_bounded(client, prompt, input_image)
        if result["state"] == "completed":
            extensions = {"PNG": "png", "JPEG": "jpg", "WEBP": "webp"}
            for index, (raw, image_format) in enumerate(result["images"]):
                extension = extensions.get(image_format, "img")
                Path(f"resultado-{index}.{extension}").write_bytes(raw)
        return result
    finally:
        await client.aio.aclose()
```

Para generar, llama a `save_generation(api_key, "Crea una imagen de…")` desde tu código asíncrono, con la clave obtenida de tu sistema de secretos. Para editar, pasa también `input_image=(Path("entrada.png").read_bytes(), "image/png")` y una instrucción de edición. Usa el tipo MIME real del archivo. El resultado conserva las imágenes decodificadas y las guarda con su extensión; comprueba después que cumplen la modificación solicitada, pues poder abrir una imagen no demuestra que su contenido sea correcto. El [flujo oficial de generación y edición](https://ai.google.dev/gemini-api/docs/generate-content/image-generation) explica las entradas y las partes de imagen de la respuesta.

Los cuatro intentos totales, sesenta segundos de presupuesto, veinte segundos por llamada y ocho segundos de tope de espera son **valores ilustrativos para este código**, no plazos de recuperación de Google. El presupuesto se aplica a las llamadas y esperas de red; la comprobación y el guardado local de la imagen añaden su propio tiempo. Ajusta los valores al tiempo que tu usuario puede esperar y al coste que tu aplicación acepta. El ejemplo solo reintenta un 503 confirmado; devuelve otros errores para que la aplicación aplique la decisión de la tabla.

Las funciones de reloj, espera y aleatoriedad permiten verificar el control de flujo sin enviar solicitudes. Este ejemplo se ha comprobado con respuestas sintéticas, reloj simulado y archivos de imagen locales; no se ha medido su tasa de recuperación contra el servicio real.

### Respeta Retry-After aunque supere tu tiempo disponible

`Retry-After` puede contener segundos o una fecha HTTP. Si pide esperar noventa segundos y a tu petición interactiva le quedan veinte, aplaza la tarea; no recortes la espera a veinte segundos para reenviarla antes de tiempo. La cabecera es opcional y su ausencia no indica cuándo se recuperará el servicio. El [estándar HTTP](https://www.rfc-editor.org/rfc/rfc9110.html#section-10.2.3) define ambos formatos.

Una fecha de ejecución diferida debe respetar ese mínimo y puede añadir variación aleatoria. No reutilices el presupuesto interactivo para mantener vivo un bucle de fondo: el trabajador de la cola necesita sus propios límites y una fecha de caducidad del trabajo.

### Un timeout deja una generación con resultado desconocido

El ejemplo no reenvía automáticamente una solicitud si pierde la conexión o agota el tiempo sin una respuesta concluyente. La generación podría haber terminado aunque tú no hayas recibido la imagen. [HTTP no garantiza que repetir un POST sea idempotente](https://www.rfc-editor.org/rfc/rfc9110.html#section-9.2.2), y este flujo no presupone deduplicación del servicio.

Conserva el identificador local del trabajo y revisa el registro del proveedor antes de autorizar otro envío. Si decides repetirlo, trátalo como otro intento que puede generar trabajo adicional. Evita que el botón del usuario y el trabajador de fondo envíen simultáneamente la misma tarea.

## Qué hacer al agotar el presupuesto: pausar, encolar o cambiar de modelo

`deferred` significa que la aplicación ha decidido dejar de enviar; **no significa que Google haya aceptado una tarea en cola**. Para ofrecer un resultado diferido, guarda la solicitud en tu propia cola con un identificador único, el modelo, las entradas necesarias, el número de intentos acumulados, la próxima fecha de ejecución permitida y la caducidad. Protege las imágenes de entrada con las mismas reglas de acceso y retención que el resto de la aplicación.

| Necesidad del usuario | Acción útil al detener los reintentos |
| --- | --- |
| Puede esperar | Guardar el trabajo y mostrar «pendiente», con una forma de consultar o cancelar |
| Necesita una respuesta inmediata | Informar de que no hay imagen todavía; ofrecer una alternativa compatible si ya existe y está autorizada |
| El contenido debe conservar una edición concreta | Mantener la imagen de entrada y las instrucciones; comprobar que cualquier alternativa admite ambas |
| Hay una generación de resultado desconocido | Revisar primero ese intento y evitar una duplicación automática |

Antes de usar un modelo de respaldo, comprueba que genera imágenes, acepta las entradas de edición que necesitas y satisface la relación de aspecto, resolución, presupuesto y tratamiento de datos de tu aplicación. Cambiar a un modelo de texto no recupera la imagen. Cambiar de proveedor o pasar a Vertex AI exige otra integración y otros requisitos; un cambio de nombre no lo resuelve.

No hay en esta guía una medición actual que permita recomendar una hora universal sin errores ni un modelo que sea siempre más estable. Si quieres programar trabajos, utiliza tus registros del mismo endpoint y modelo, con franjas horarias y volumen de solicitudes comparables. Reducir simultaneidad y aplazar trabajo resulta más controlable que aumentar los reintentos basándose en porcentajes antiguos.

## Evita que todos los trabajadores prueben la recuperación a la vez

Limita las solicitudes simultáneas hacia cada endpoint y modelo. Los reintentos también consumen ese límite. Cuando acumules fallos suficientes según tus propias mediciones, un interruptor de protección —*circuit breaker*— puede pausar nuevas llamadas y dejar los trabajos pendientes.

![Circuit breaker con una sola reserva de sondeo atómica y verificación de una imagen antes de reanudar](https://blog.laozhang.ai/posts/es/nano-banana-2-503-overloaded-fix/img/circuit-breaker-states.webp)

El paso delicado es el estado **semiabierto**. Esperar un plazo y permitir que todos los trabajadores vuelvan a enviar reproduce la ráfaga que quieres evitar. Una implementación segura necesita esta secuencia:

1. En estado abierto, rechaza el permiso de envío y conserva la tarea pendiente.
2. Cuando llegue la próxima fecha de prueba, reserva **un único permiso de sondeo de forma atómica**. En un proceso basta una protección compartida por sus trabajadores; con varias instancias necesitas una reserva compartida con vencimiento.
3. Mientras ese permiso esté ocupado, los demás trabajadores siguen esperando. El propietario hace una sola solicitud, sin una cadena interna de reintentos.
4. Si recibe una imagen utilizable, libera el permiso y reanuda el trabajo gradualmente. Si recibe otro 503, vuelve a abrir el circuito. Si el resultado es desconocido, no declares el servicio recuperado y registra la ambigüedad.

Incluye un identificador de la reserva para que una respuesta tardía de un sondeo anterior no cierre un circuito que ya se ha vuelto a abrir. El vencimiento evita dejar bloqueado el sistema cuando muere un trabajador. Los umbrales y tiempos dependen de tu carga: no existe aquí un «cinco errores y treinta segundos» validado específicamente para Nano Banana 2. El sondeo genera trabajo real y puede tener coste; no lo multipliques como una comprobación gratuita.

## ¿Sirve Batch API para evitar el 503?

**Batch es una opción para trabajos no urgentes, no una garantía contra los fallos.** La ficha de `gemini-3.1-flash-image` indica que admite Batch. La [documentación de Batch API](https://ai.google.dev/gemini-api/docs/batch-api) describe procesamiento asíncrono con un objetivo de veinticuatro horas, no un plazo garantizado.

Si ese tiempo encaja con tu trabajo, envía el lote una vez y conserva su nombre para consultar el estado. Un trabajo puede fallar, cancelarse o caducar; incluso cuando termina correctamente, revisa los errores de cada elemento y las partes de imagen. Un estado de éxito del lote no sustituye la validación de cada imagen.

Tu cola local y Batch resuelven tareas distintas: la primera organiza el trabajo de tu aplicación; la segunda es el servicio asíncrono de Google. No reenvíes todo el lote porque una consulta de estado haya fallado, ni mantengas la solicitud interactiva esperando su finalización.

## Preguntas frecuentes

### ¿Cuánto tarda en desaparecer el error 503 de Nano Banana 2?

No hay un tiempo fijo que puedas deducir del código 503. Respeta `Retry-After` si aparece y usa tu presupuesto de espera para decidir cuándo aplazar el trabajo. Puedes consultar el [estado de Google AI Studio](https://aistudio.google.com/status), contrastándolo con el endpoint que utilizas; una respuesta aislada no confirma una caída global.

### ¿Google cobra las solicitudes que devuelven un 503?

No es correcto prometer que todos los 503 son gratuitos. La [FAQ de facturación de Gemini API](https://ai.google.dev/gemini-api/docs/billing) menciona explícitamente que los errores 400 y 500 no generan cargos por tokens, aunque cuentan para la cuota. Ese texto no aclara todos los casos de 503, los cobros de intermediarios ni una desconexión después de generar. Consulta el uso y la facturación del servicio que te ha atendido; no bases un bucle ilimitado de reintentos en esa supuesta exención.

### ¿Pagar más o aumentar la cuota corrige el error 503?

No garantiza capacidad disponible para una solicitud que devuelve 503. Ante un 429, identifica primero si has alcanzado un límite temporal, una cuota u otra restricción indicada en la respuesta. La acción puede ser reducir la frecuencia o revisar el límite aplicable; pagar no es una solución universal para ambos errores.

### ¿Por qué el código se detiene con 200 si no hay imagen?

Porque el objetivo es obtener una imagen, no únicamente completar una llamada HTTP. Inspecciona `candidates`, las partes de contenido, los motivos de finalización y `prompt_feedback`. Puede faltar la salida de imagen por distintos motivos, incluidos el contenido solicitado, un bloqueo o la lectura incorrecta de la respuesta; no atribuyas todos los casos a seguridad ni les apliques los reintentos de un 503.

## Documentación oficial

Los parámetros de la solicitud, los precios y las reglas de cobro están en la documentación para desarrolladores de LaoZhang API: [facturación y fallos en la generación de imágenes](https://docs.laozhang.ai/en/api-capabilities/image-billing-and-failures).

*Aviso: [laozhang.ai es un servicio propio](https://blog.laozhang.ai/es/about#laozhang). Sus precios son nuestra tarifa, no una comparación independiente.*

## Fuentes

Páginas externas que cita esta guía, en el orden en que aparecen. Última actualización: 2026-10-07.

- [ficha actual de Nano Banana 2](https://ai.google.dev/gemini-api/docs/models/gemini-3.1-flash-image) (ai.google.dev)
- [503 significa que el servicio no puede atender la solicitud en ese momento](https://www.rfc-editor.org/rfc/rfc9110.html) (rfc-editor.org)
- [guía de resolución de problemas de Google](https://ai.google.dev/gemini-api/docs/troubleshooting) (ai.google.dev)
- [referencia de errores de Interactions](https://ai.google.dev/gemini-api/docs/api-errors) (ai.google.dev)
- [código de la rama main del SDK consultado el 6 de octubre](https://github.com/googleapis/python-genai/blob/main/google/genai/_api_client.py) (github.com)
- [tipos del SDK](https://github.com/googleapis/python-genai/blob/main/google/genai/types.py) (github.com)
- [flujo oficial de generación y edición](https://ai.google.dev/gemini-api/docs/generate-content/image-generation) (ai.google.dev)
- [documentación de Batch API](https://ai.google.dev/gemini-api/docs/batch-api) (ai.google.dev)
- [estado de Google AI Studio](https://aistudio.google.com/status) (aistudio.google.com)
- [FAQ de facturación de Gemini API](https://ai.google.dev/gemini-api/docs/billing) (ai.google.dev)
