{"record":{"id":"facfc1a332e87919","repo":"jackwener/OpenCLI","slug":"timeout-must-be-a-positive-integer-seconds-facfc1","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/trae-cn/utils.js","lineNumber":32,"sourceCode":"  'shred',\n  'dd',\n  'truncate',\n  'kill',\n  'chmod',\n  'mv',\n  'copy',\n  'move',\n  'Set-Content',\n  'Out-File',\n  'mkfs',\n  'git force/delete/hard/filter/rebase operations',\n  'destructive database commands',\n];\n\nexport function normalizeTimeout(value, fallback = 60) {\n  const timeout = value === undefined || value === null ? fallback : Number(value);\n  if (!Number.isInteger(timeout) || timeout < 1) {\n    throw new ArgumentError('--timeout must be a positive integer (seconds)');\n  }\n  return timeout;\n}\n\nexport function normalizeLimit(value, fallback = 20) {\n  const limit = value === undefined || value === null ? fallback : Number(value);\n  if (!Number.isInteger(limit) || limit < 1 || limit > 200) {\n    throw new ArgumentError('--limit must be an integer between 1 and 200');\n  }\n  return limit;\n}\n\nexport function normalizeMaxChars(value, fallback = 6000) {\n  const maxChars = value === undefined || value === null ? fallback : Number(value);\n  if (!Number.isInteger(maxChars) || maxChars < 0 || maxChars > 1_000_000) {\n    throw new ArgumentError('--max-chars must be an integer between 0 and 1000000');\n  }\n  return maxChars;","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/trae-cn/utils.js#L14-L50","documentation":"normalizeTimeout in utils.js throws an ArgumentError when the --timeout value is not an integer >= 1 (seconds). The value passes through Number(), so NaN, floats, 0, negatives, and non-numeric strings all fail the Number.isInteger/limit check.","triggerScenarios":"Running any trae-cn command with `--timeout 0`, `--timeout -5`, `--timeout 2.5`, `--timeout abc`, or `--timeout \"\"` (empty string coerces to 0).","commonSituations":"Scripts interpolating empty/unset variables into --timeout; typo'd units like `--timeout 90s` or `--timeout 1.5m`; assuming 0 means 'no timeout'.","solutions":["Pass a positive whole number of seconds, e.g. --timeout 60.","Omit --timeout to use the 60-second default.","Fix shell scripts so empty variables aren't passed: use ${VAR:-60} or skip the flag when unset.","Convert minutes to seconds yourself: --timeout 120 for 2 minutes."],"exampleFix":"// before\nopencli trae-cn ask \"hi\" --timeout \"$TIMEOUT\"   # TIMEOUT empty -> 0\n// after\nopencli trae-cn ask \"hi\" --timeout \"${TIMEOUT:-60}\"","handlingStrategy":"validation","validationCode":"function assertTimeout(v, fallback = 60) {\n  const t = v === undefined || v === null ? fallback : Number(v);\n  if (!Number.isInteger(t) || t < 1) throw new Error(`Invalid --timeout: ${JSON.stringify(v)}; use a positive integer (seconds)`);\n  return t;\n}","typeGuard":"function isValidTimeout(v) {\n  return typeof v === 'number' ? Number.isInteger(v) && v >= 1 : v === undefined || v === null || String(v).trim() !== '' && Number.isInteger(Number(v)) && Number(v) >= 1;\n}","tryCatchPattern":"try {\n  await runCommand(['--timeout', String(userTimeout)]);\n} catch (e) {\n  if (e instanceof ArgumentError && e.message.includes('--timeout')) {\n    console.error('Falling back to default timeout 60s');\n    return runCommand([]);\n  }\n  throw e;\n}","preventionTips":["Always pass whole seconds; convert minutes/units yourself.","Use ${VAR:-60} patterns so empty env vars never reach the flag.","Remember 0 is invalid, not 'unlimited'.","Validate user input at the script boundary before invoking the CLI."],"tags":["argument-validation","cli","input-validation"],"backgroundTag":"invalid-cli-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}