{"record":{"id":"d6f827192b4f604b","repo":"jackwener/OpenCLI","slug":"timeout-must-be-a-positive-integer-seconds-d6f827","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/chatgpt/image.js","lineNumber":89,"sourceCode":"    defaultFormat: 'plain',\n    args: [\n        { name: 'prompt', positional: true, required: true, help: 'Image prompt to send to ChatGPT' },\n        { name: 'image', help: 'Local image path to attach before prompting; comma-separated paths are supported' },\n        { name: 'project', valueRequired: true, help: 'Start image generation inside a ChatGPT project ID or /g/g-p-<id> URL' },\n        { name: 'op', help: 'Output directory (default: ~/Pictures/chatgpt)' },\n        { name: 'sd', type: 'boolean', default: false, help: 'Skip download shorthand; only show ChatGPT 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 imagePaths = parseImagePaths(kwargs.image);\n        const outputDir = resolveOutputDir(kwargs.op);\n        const skipDownloadRaw = kwargs.sd;\n        const skipDownload = skipDownloadRaw === '' || skipDownloadRaw === true || normalizeBooleanFlag(skipDownloadRaw);\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 preparedImages = imagePaths.length ? await prepareChatGPTImagePaths(imagePaths) : { ok: true, paths: [] };\n        if (!preparedImages.ok) {\n            throw new ArgumentError(preparedImages.reason);\n        }\n\n        // Navigate with full reload to clear React sidebar state before editing the draft.\n        if (kwargs.project) {\n            await navigateToProject(page, kwargs.project);\n        } else {\n            await page.goto(`https://${CHATGPT_DOMAIN}/new`, { settleMs: 2000 });\n        }\n        await clearChatGPTDraft(page);\n\n        if (imagePaths.length) {\n            let upload;\n            try {\n                upload = await uploadChatGPTImages(page, preparedImages.paths);","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/chatgpt/image.js#L71-L107","documentation":"The `chatgpt image` command validates the --timeout kwarg and throws ArgumentError when it is not an integer >= 1. Since --timeout is declared as type int with default 240, this fires when a non-integer (e.g. a string like '30s' or 'abc', or a float) reaches the command body and fails Number.isInteger(timeout) || timeout < 1.","triggerScenarios":"Calling `opencli chatgpt image \"prompt\" --timeout 0`, --timeout -5, --timeout abc, --timeout 2.5, or passing an unparseable value through a wrapper that does not coerce it to int.","commonSituations":"Typo like `--timeout=30s`; scripts passing environment variables as strings; automation passing null/undefined explicitly; unit confusion (passing milliseconds like 60000 expecting it to work — it would pass validation but run far too long, whereas 0 or '60 sec' fails here).","solutions":["Pass a plain positive integer, e.g. --timeout 240.","Remove surrounding units/characters from the value ('30s' → '30').","In scripts, coerce before calling: timeout = parseInt(process.env.TIMEOUT, 10) and check Number.isInteger.","Omit --timeout entirely to use the 240s default."],"exampleFix":"// before\nopencli chatgpt image \"a red fox\" --timeout 30s\n// after\nopencli chatgpt image \"a red fox\" --timeout 30","handlingStrategy":"validation","validationCode":"function coerceTimeout(value, fallback = 240) {\n  const n = typeof value === 'number' ? value : parseInt(String(value ?? ''), 10);\n  return Number.isInteger(n) && n >= 1 ? n : fallback;\n}\nconst timeout = coerceTimeout(process.env.IMAGE_TIMEOUT ?? '240');","typeGuard":"function isValidTimeout(v) {\n  return Number.isInteger(v) && v >= 1;\n}","tryCatchPattern":"try {\n  await run('chatgpt image', prompt, '--timeout', String(timeout));\n} catch (err) {\n  if (String(err.message).includes('--timeout must be a positive integer')) {\n    return run('chatgpt image', prompt); // use the 240s default\n  }\n  throw err;\n}","preventionTips":["Always pass plain integers (no units, no decimals) to --timeout","Coerce env vars / CLI strings with parseInt before forwarding","Rely on the 240s default when unsure","Add a pre-call assertion: Number.isInteger(t) && t >= 1"],"tags":["argument-validation","timeout","chatgpt"],"backgroundTag":"invalid-argument-value","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}