CherryHQ/cherry-studio · warning · Error
Invalid duration: "${duration}". Use formats like '30m', '2h
Error message
Invalid duration: "${duration}". Use formats like '30m', '2h', '1h30m'. What it means
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.
Source
Thrown at src/main/ai/mcp/servers/cherryAutonomyTools.ts:59
*/
getKnowledgeBaseIds: () => string[]
}
/**
* Parse a human-friendly duration string (e.g. '30m', '2h', '1h30m') into minutes.
*/
function parseDurationToMinutes(duration: string): number {
let totalMinutes = 0
const hourMatch = duration.match(/(\d+)\s*h/i)
const minMatch = duration.match(/(\d+)\s*m/i)
if (hourMatch) totalMinutes += parseInt(hourMatch[1], 10) * 60
if (minMatch) totalMinutes += parseInt(minMatch[1], 10)
if (totalMinutes === 0) {
const raw = parseInt(duration, 10)
if (!isNaN(raw) && raw > 0) return raw
throw new Error(`Invalid duration: "${duration}". Use formats like '30m', '2h', '1h30m'.`)
}
return totalMinutes
}
const CRON_TOOL: Tool = {
name: CRON_TOOL_NAME,
description:
"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.",
inputSchema: {
type: 'object',
properties: {
action: {
type: 'string',
enum: ['add', 'list', 'remove'],
description: 'The action to perform'
},
name: {View on GitHub (pinned to 726446b54c)
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'.
Example fix
// before — unsupported unit
addJob({ every: '1d', ... })
// after — express in supported h/m units
addJob({ every: '24h', ... })
// or validate first
function isValidEvery(v: string) { return /^\s*(\d+\s*h)?(\s*\d+\s*m)?\s*$/i.test(v) && /\d/.test(v) } Defensive patterns
Strategy: validation
Validate before calling
function validateEvery(v: unknown): string {
if (typeof v !== 'string') throw new Error('every must be a string')
const trimmed = v.trim()
const ok = /^(\d+\s*h)?(\s*\d+\s*m)?$/i.test(trimmed) && /\d/.test(trimmed)
if (!ok) {
const n = parseInt(trimmed, 10)
if (isNaN(n) || n <= 0) throw new Error(`Invalid duration: "${v}". Use '30m', '2h', '1h30m'.`)
return `${n}m`
}
return trimmed.replace(/\s+/g, '')
} Type guard
function isValidDuration(v: unknown): v is string {
if (typeof v !== 'string') return false
const t = v.trim()
if (/^(\d+\s*h)?(\s*\d+\s*m)?$/i.test(t) && /\d/.test(t)) return true
const n = parseInt(t, 10)
return !isNaN(n) && n > 0
} Try / catch
try {
const minutes = parseDurationToMinutes(validateEvery(args.every))
} catch (e) {
return { content: [{ type: 'text', text: e.message }], isError: true }
} Prevention
- 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.
When it happens
Trigger: Passing 'every' with an unsupported unit: '1d', '45s', '500ms', 'weekly', negative numbers, zero, empty string, or pure non-numeric text.
Common situations: 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'.
Related errors
- InvalidParams
- MethodNotFound
- Private key must be a non-empty string
- Invalid PEM format: missing BEGIN/END markers or key content
- Private key content is empty after cleaning
AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12).
Data as JSON: /api/errors/cdb9645b942e1c6f.
Report an issue: GitHub.