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
- Re-run with a higher --timeout value (e.g. --timeout 300)
- Simplify the prompt or request fewer images per run
- 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
- Pass an explicit --timeout of 120-300s for image generation
- Request fewer images per prompt to shorten generation time
- Retry once with doubled timeout before reporting failure
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
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Unexpected 12306 probe: ${JSON.stringify(probe)}
- ChatGPT did not create a conversation URL after sending the
- ChatWise response
- Could not switch to ${wantModel} model
- No Claude response appeared within ${timeoutSeconds}s. Re-ru
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/7e3f87d5b2ca8456.
Report an issue: GitHub.