decolua/9router · error

NanoBanana polling timeout

Error message

NanoBanana polling timeout

What it means

Thrown when the NanoBanana task never reaches a terminal state within POLL_TIMEOUT_MS: the polling loop exits and this error is raised unconditionally at nanobanana.js:53. The task was submitted successfully and every poll returned 200, but successFlag stayed 0 (pending/running) until the deadline.

Source

Thrown at open-sse/handlers/imageProviders/nanobanana.js:53

  },
  // Async: parse submit → poll until SUCCESS, return raw poll data
  async parseResponse(response, { headers }) {
    const submitData = await response.json();
    if (submitData.code !== 200) throw new Error(submitData.msg || "NanoBanana submit failed");
    const taskId = submitData.data?.taskId;
    if (!taskId) throw new Error("NanoBanana: no taskId returned");
    const pollUrl = `${POLL_BASE}?taskId=${encodeURIComponent(taskId)}`;
    const deadline = Date.now() + POLL_TIMEOUT_MS;
    while (Date.now() < deadline) {
      await sleep(POLL_INTERVAL_MS);
      const r = await fetch(pollUrl, { headers });
      if (!r.ok) throw new Error(`NanoBanana status ${r.status}`);
      const s = await r.json();
      const flag = s.data?.successFlag;
      if (flag === 1) return s.data;
      if (flag === 2 || flag === 3) throw new Error(s.data?.errorMessage || "NanoBanana generation failed");
    }
    throw new Error("NanoBanana polling timeout");
  },
  normalize: (responseBody, prompt) => {
    const url = responseBody.response?.resultImageUrl || responseBody.response?.originImageUrl;
    if (url) return { created: nowSec(), data: [{ url, revised_prompt: prompt }] };
    return { created: nowSec(), data: [] };
  },
};

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Increase POLL_TIMEOUT_MS (or pass a larger per-provider timeout) if generations are simply slow — check typical latency for your model/numImages.
  2. Log the last poll payload before the throw to confirm the response shape still contains data.successFlag; adjust parsing if the provider changed its schema.
  3. Verify POLL_BASE/imageConfig.pollUrl points at the real record-info endpoint (a wrong endpoint can 200 forever without status).
  4. Reduce numImages (body.n) or prompt complexity to shorten generation time and retry.
  5. As a hardening step, treat a very old taskId as failed: re-submit if polling exceeds, say, 2x your historical p99 duration.
Defensive patterns

Strategy: validation

Validate before calling

// Validate poll config and timeout budget before submitting an async task
const cfg = PROVIDER_MEDIA["nanobanana"]?.imageConfig;
if (!cfg?.pollUrl) throw new Error("NanoBanana pollUrl not configured");
import { POLL_TIMEOUT_MS } from "./_base.js";
if (POLL_TIMEOUT_MS < 60_000) console.warn("NanoBanana POLL_TIMEOUT_MS is low for large generations");

Type guard

function hasTerminalStatus(s) {
  const flag = s?.data?.successFlag;
  return flag === 1 || flag === 2 || flag === 3; // only these end the loop; anything else = still pending
}

Try / catch

try {
  const data = await imageProvider.parseResponse(response, { headers });
} catch (e) {
  if (e.message === "NanoBanana polling timeout") {
    // Task may still complete upstream — inform the caller rather than reporting a hard failure
    return { error: { code: "poll_timeout", retryable: true, detail: "task still pending after timeout" } };
  }
  throw e;
}

Prevention

When it happens

Trigger: The while (Date.now() < deadline) loop in open-sse/handlers/imageProviders/nanobanana.js:44-52 expires with `s.data?.successFlag` never equal to 1, 2, or 3 — e.g. the provider is still queued after POLL_TIMEOUT_MS, or returns an unexpected shape (s.data missing / successFlag absent) forever.

Common situations: Very large numImages or high upstream queue load exceeding the fixed POLL_TIMEOUT_MS from _base.js; the callBackUrl dummy value causing upstream to stall; provider schema change so successFlag is no longer under s.data (poll looks pending forever); wrong pollUrl returning 200 with a non-status body.

Understand the failure class

Related errors


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/b120dfd11b7a1881. Report an issue: GitHub.