{"record":{"id":"14c9a12201809251","repo":"jackwener/OpenCLI","slug":"timeout-must-be-a-positive-integer-seconds-14c9a1","errorCode":null,"errorMessage":"--timeout must be a positive integer (seconds)","messagePattern":"--timeout must be a positive integer \\(seconds\\)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/gemini/image.js","lineNumber":84,"sourceCode":"    navigateBefore: false,\n    defaultFormat: 'plain',\n    args: [\n        { name: 'prompt', positional: true, required: true, help: 'Image prompt to send to Gemini' },\n        { name: 'rt', default: '1:1', help: 'Ratio shorthand for aspect ratio (1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3)' },\n        { name: 'st', default: '', help: 'Style shorthand, e.g. anime, icon, watercolor' },\n        { name: 'op', default: '~/tmp/gemini-images', help: 'Output directory shorthand' },\n        { name: 'sd', type: 'boolean', default: false, help: 'Skip download shorthand; only show Gemini page link' },\n        { name: 'timeout', type: 'int', required: false, default: 240, help: 'Max seconds for the overall command (default: 240)' },\n    ],\n    columns: ['status', 'file', 'link'],\n    func: async (page, kwargs) => {\n        const prompt = kwargs.prompt;\n        const ratio = normalizeRatio(String(kwargs.rt ?? '1:1'));\n        const style = String(kwargs.st ?? '').trim();\n        const outputDir = resolveOutputDir(kwargs.op);\n        const timeout = kwargs.timeout;\n        if (!Number.isInteger(timeout) || timeout < 1) {\n            throw new ArgumentError('--timeout must be a positive integer (seconds)');\n        }\n        const startFresh = true;\n        const skipDownloadRaw = kwargs.sd;\n        const skipDownload = skipDownloadRaw === '' || skipDownloadRaw === true || normalizeBooleanFlag(skipDownloadRaw);\n        const effectivePrompt = buildImagePrompt(prompt, {\n            ratio,\n            style: style || undefined,\n        });\n        if (startFresh)\n            await startNewGeminiChat(page);\n        const beforeUrls = await getGeminiVisibleImageUrls(page);\n        await sendGeminiMessage(page, effectivePrompt);\n        const urls = await waitForGeminiImages(page, beforeUrls, timeout);\n        const link = await currentGeminiLink(page);\n        if (!urls.length) {\n            throw new EmptyResultError('gemini image', `No generated image was detected. Open ${link} and check whether Gemini produced one.`);\n        }\n        if (skipDownload) {","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/gemini/image.js#L66-L102","documentation":"The gemini image command validates --timeout before generating; it must be an integer >= 1 (seconds) or ArgumentError('--timeout must be a positive integer (seconds)') is thrown. The timeout bounds how long the command waits for Gemini to produce an image after the prompt is sent. Validation happens up front, before any chat is started or message sent.","triggerScenarios":"Calling `opencli gemini image` with --timeout omitted, fractional (e.g. 1.5), zero, negative, or non-numeric ('60s', 'minute').","commonSituations":"Duration strings with units pasted from docs; computed float from config (e.g. seconds*1.5); unset env var interpolated into the flag; YAML/JSON pipeline quoting the number as a string with characters like 'ms'.","solutions":["Pass --timeout as a plain positive integer, e.g. --timeout 90 (image generation can be slow, prefer generous values)","Convert any units to whole seconds before invoking","Guard script-interpolated values: default to an integer when unset, e.g. TIMEOUT=\"${TIMEOUT:-120}\"","Round computed values and re-check Number.isInteger in wrappers"],"exampleFix":"// before\nopencli gemini image --prompt \"a cat\" --timeout 1.5m\n// after\nopencli gemini image --prompt \"a cat\" --timeout 90","handlingStrategy":"validation","validationCode":"const t = Number(process.env.IMG_TIMEOUT ?? 120);\nif (!Number.isInteger(t) || t < 1) throw new Error('--timeout must be a positive integer (seconds)');","typeGuard":"const isPositiveInt = (v) => typeof v === 'number' && Number.isInteger(v) && v >= 1;","tryCatchPattern":"try {\n  await run(['gemini','image','--prompt',p,'--timeout',String(t)]);\n} catch (e) {\n  if (String(e.message).includes('--timeout must be a positive integer')) {\n    console.error('Pass --timeout as whole seconds, e.g. --timeout 120');\n  } else throw e;\n}","preventionTips":["Convert any duration strings to integer seconds before invoking","Default env-derived timeouts to a fixed integer when unset","Image generation is slow; use generous values like 90-120 seconds"],"tags":["validation","argument-error","cli","timeout"],"backgroundTag":"invalid-cli-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}