jackwener/OpenCLI · error · TimeoutError

'gemini image', timeoutSeconds, 'Gemini was still generating

Error message

'gemini image', timeoutSeconds, 'Gemini was still generating at the deadline. Re-run with a higher --timeout.'

What it means

TimeoutError thrown by the Gemini image polling helper after the poll loop exhausted its attempts (maxPolls) while the UI still reported 'still generating'. The library polls the Gemini response DOM for stable image URLs and gives up at the user-supplied deadline rather than returning partial results.

Source

Thrown at clis/gemini/utils.js:2425

        }
        if (stillGenerating)
            continue;
        const urls = (await getGeminiVisibleImageUrls(page)).filter((url) => !beforeSet.has(url));
        if (urls.length === 0)
            continue;
        const key = urls.join('\n');
        const prevKey = lastUrls.join('\n');
        if (key == prevKey)
            stableCount += 1;
        else {
            lastUrls = urls;
            stableCount = 1;
        }
        if (stableCount >= 2 || index === maxPolls - 1)
            return lastUrls;
    }
    if (stillGenerating) {
        throw new TimeoutError('gemini image', timeoutSeconds, 'Gemini was still generating at the deadline. Re-run with a higher --timeout.');
    }
    return lastUrls;
}
export async function exportGeminiImages(page, urls) {
    await ensureGeminiPage(page);
    const urlsJson = JSON.stringify(urls);
    const result = await page.evaluate(`
    (async (targetUrls) => {
      const blobToDataUrl = (blob) => new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.onloadend = () => resolve(String(reader.result || ''));
        reader.onerror = () => reject(new Error('Failed to read blob'));
        reader.readAsDataURL(blob);
      });

      const inferMime = (value, fallbackUrl) => {
        if (value) return value;
        const lower = String(fallbackUrl || '').toLowerCase();

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-run with a higher --timeout value (e.g. --timeout 300)
  2. Simplify the prompt or request fewer images per run
  3. Check network/browser performance and retry when Gemini responds faster

Example fix

// before
opencli gemini image "a watercolor castle"
// after
opencli gemini image "a watercolor castle" --timeout 300
Defensive patterns

Strategy: retry

Validate before calling

const timeoutSeconds = Number(opts.timeout ?? 120);
if (!Number.isFinite(timeoutSeconds) || timeoutSeconds < 60) {
  throw new Error('gemini image needs a generous --timeout (>= 60s recommended, 300s for multiple images)');
}

Try / catch

import { TimeoutError } from 'opencli/errors';
try {
  const urls = await waitForGeminiResponse(page, baseline, prompt, timeoutSeconds);
} catch (err) {
  if (err instanceof TimeoutError && err.kind === 'gemini image') {
    return retryWith({ timeout: timeoutSeconds * 2 });
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling the gemini image command (exportGeminiImages/waitForGeminiResponse flow at clis/gemini/utils.js:2425) when Gemini has not finished generating all images within timeoutSeconds; slow model, long prompt, or too-low --timeout value.

Common situations: Default timeout too short for image generation; browser/session slowness; Gemini under heavy load producing images slowly; generating multiple high-resolution images.

Understand the failure class

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/7e3f87d5b2ca8456. Report an issue: GitHub.