{"record":{"id":"cdb9645b942e1c6f","repo":"CherryHQ/cherry-studio","slug":"invalid-duration-duration-use-formats-like","errorCode":null,"errorMessage":"Invalid duration: \"${duration}\". Use formats like '30m', '2h', '1h30m'.","messagePattern":"Invalid duration: \"(.+?)\"\\. Use formats like '30m', '2h', '1h30m'\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/main/ai/mcp/servers/cherryAutonomyTools.ts","lineNumber":59,"sourceCode":"   */\n  getKnowledgeBaseIds: () => string[]\n}\n\n/**\n * Parse a human-friendly duration string (e.g. '30m', '2h', '1h30m') into minutes.\n */\nfunction parseDurationToMinutes(duration: string): number {\n  let totalMinutes = 0\n  const hourMatch = duration.match(/(\\d+)\\s*h/i)\n  const minMatch = duration.match(/(\\d+)\\s*m/i)\n\n  if (hourMatch) totalMinutes += parseInt(hourMatch[1], 10) * 60\n  if (minMatch) totalMinutes += parseInt(minMatch[1], 10)\n\n  if (totalMinutes === 0) {\n    const raw = parseInt(duration, 10)\n    if (!isNaN(raw) && raw > 0) return raw\n    throw new Error(`Invalid duration: \"${duration}\". Use formats like '30m', '2h', '1h30m'.`)\n  }\n\n  return totalMinutes\n}\n\nconst CRON_TOOL: Tool = {\n  name: CRON_TOOL_NAME,\n  description:\n    \"Manage scheduled tasks. Use action 'add' to create a recurring or one-time job, 'list' to see all jobs, or 'remove' to delete a job. For one-time jobs, use the 'at' field with an RFC3339 timestamp.\",\n  inputSchema: {\n    type: 'object',\n    properties: {\n      action: {\n        type: 'string',\n        enum: ['add', 'list', 'remove'],\n        description: 'The action to perform'\n      },\n      name: {","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/mcp/servers/cherryAutonomyTools.ts#L41-L77","documentation":"parseDurationToMinutes throws when the input matches neither /(\\d+)\\s*h/i nor /(\\d+)\\s*m/i, AND parseInt(duration, 10) is NaN or <= 0. It is used to parse the cron tool's 'every' interval field. Accepted forms are like '30m', '2h', '1h30m', or a bare positive integer of minutes.","triggerScenarios":"Passing 'every' with an unsupported unit: '1d', '45s', '500ms', 'weekly', negative numbers, zero, empty string, or pure non-numeric text.","commonSituations":"Agent or user assumes ISO-8601 durations (P1D) or seconds are supported; passes '0' or '-5'; copies a cron expression into the every field; includes extra spaces or words like 'every 30m'.","solutions":["Use only hours/minutes forms: '30m', '2h', '1h30m', or a positive integer minute count.","Convert seconds/days beforehand: 90s -> '2m' (round up), 1d -> '24h'.","Strip surrounding text and validate against /^(\\d+\\s*h)?(\\s*\\d+\\s*m)?$/i before calling.","For one-shot times use 'at' with an RFC3339 timestamp instead; for cron schedules use 'cron'."],"exampleFix":"// before — unsupported unit\naddJob({ every: '1d', ... })\n\n// after — express in supported h/m units\naddJob({ every: '24h', ... })\n// or validate first\nfunction isValidEvery(v: string) { return /^\\s*(\\d+\\s*h)?(\\s*\\d+\\s*m)?\\s*$/i.test(v) && /\\d/.test(v) }","handlingStrategy":"validation","validationCode":"function validateEvery(v: unknown): string {\n  if (typeof v !== 'string') throw new Error('every must be a string')\n  const trimmed = v.trim()\n  const ok = /^(\\d+\\s*h)?(\\s*\\d+\\s*m)?$/i.test(trimmed) && /\\d/.test(trimmed)\n  if (!ok) {\n    const n = parseInt(trimmed, 10)\n    if (isNaN(n) || n <= 0) throw new Error(`Invalid duration: \"${v}\". Use '30m', '2h', '1h30m'.`)\n    return `${n}m`\n  }\n  return trimmed.replace(/\\s+/g, '')\n}","typeGuard":"function isValidDuration(v: unknown): v is string {\n  if (typeof v !== 'string') return false\n  const t = v.trim()\n  if (/^(\\d+\\s*h)?(\\s*\\d+\\s*m)?$/i.test(t) && /\\d/.test(t)) return true\n  const n = parseInt(t, 10)\n  return !isNaN(n) && n > 0\n}","tryCatchPattern":"try {\n  const minutes = parseDurationToMinutes(validateEvery(args.every))\n} catch (e) {\n  return { content: [{ type: 'text', text: e.message }], isError: true }\n}","preventionTips":["Use only h/m units or a positive integer minute count.","Convert seconds/days before passing (90s -> 2m, 1d -> 24h).","Use 'cron' or 'at' for non-interval schedules."],"tags":["validation","cron","scheduling","duration","cherry-autonomy"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}