{"record":{"id":"3f92c29e3442abb5","repo":"cube-js/cube","slug":"can-t-parse-date-to","errorCode":null,"errorMessage":"Can't parse date: '${to}'","messagePattern":"Can't parse date: '(.+?)'","errorType":"validation","errorClass":"UserError","httpStatus":null,"severity":"error","filePath":"packages/cubejs-api-gateway/src/date-parser.js","lineNumber":81,"sourceCode":"    momentRange = [\n      moment.tz(timezone).startOf('day').add(1, 'day'),\n      moment.tz(timezone).endOf('day').add(1, 'day')\n    ];\n  } else if (dateString.match(/^from (.*) to (.*)$/)) {\n    let [, from, to] = dateString.match(/^from(.{0,50})to(.{0,50})$/);\n    from = from.trim();\n    to = to.trim();\n\n    const current = moment(now).tz(timezone);\n    const fromResults = parse(from.trim(), new Date(current.format(moment.HTML5_FMT.DATETIME_LOCAL_MS)));\n    const toResults = parse(to.trim(), new Date(current.format(moment.HTML5_FMT.DATETIME_LOCAL_MS)));\n\n    if (!Array.isArray(fromResults) || !fromResults.length) {\n      throw new UserError(`Can't parse date: '${from}'`);\n    }\n\n    if (!Array.isArray(toResults) || !toResults.length) {\n      throw new UserError(`Can't parse date: '${to}'`);\n    }\n\n    const exactGranularity = ['second', 'minute', 'hour'].find(g => dateString.indexOf(g) !== -1) || 'day';\n    momentRange = [\n      momentFromResult(fromResults[0].start, timezone),\n      momentFromResult(toResults[0].start, timezone)\n    ];\n\n    momentRange = [momentRange[0].startOf(exactGranularity), momentRange[1].endOf(exactGranularity)];\n  } else {\n    const current = moment(now).tz(timezone);\n    const results = parse(dateString, new Date(current.format(moment.HTML5_FMT.DATETIME_LOCAL_MS)));\n\n    if (!results?.length) {\n      throw new UserError(`Can't parse date: '${dateString}'`);\n    }\n\n    const exactGranularity = ['second', 'minute', 'hour'].find(g => dateString.indexOf(g) !== -1) || 'day';","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/packages/cubejs-api-gateway/src/date-parser.js#L63-L99","documentation":"Same as the 'from' check: in a 'from X to Y' date-range string, the 'to' half failed chrono-node parsing so dateParser throws this UserError. Cube requires both halves of the range to resolve to concrete dates to build the query time range.","triggerScenarios":"dateRange entry like ['from last week to whenever'], ['from today to 2024-13-99'], or any string after 'to' that chrono-node cannot interpret (empty string, misspelled month, unsupported locale format).","commonSituations":"Dynamic filter UIs where the end-date field is empty or contains a free-text placeholder; locale-formatted dates produced with toLocaleDateString in non-US formats; typo'd or truncated strings concatenated into 'from ... to ...'.","solutions":["Fix the string after 'to' (shown in the error) to a chrono-parseable date, e.g. 'to 2024-02-28' or 'to now'","Use built-in relative ranges ('last month', 'today') or explicit ISO arrays ['2024-01-01','2024-01-31'] instead","Validate the end date with chrono-node in the client before sending the query","If the end date can be empty, substitute the current date server-side before calling the API"],"exampleFix":"// before\n{ dateRange: ['from last week to till now'] }\n// after\n{ dateRange: ['from last week to now'] }","handlingStrategy":"validation","validationCode":"import { parse } from 'chrono-node';\nconst m = range.match(/^from(.{0,50})to(.{0,50})$/i);\nconst to = m ? m[2].trim() : '';\nif (!parse(to).length) throw new Error(`Invalid 'to' date in range: '${to}'`);","typeGuard":"const isParseableToDate = (s) => typeof s === 'string' && /^from(.{0,50})to(.{0,50})$/i.test(s) && chronoParse(s.match(/^from(.{0,50})to(.{0,50})$/i)[2].trim()).length > 0;","tryCatchPattern":"try {\n  await cube.load({ ...query, dateRange: [from, to] });\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith(\"Can't parse date:\")) {\n    console.error(`Invalid range end ${e.message}`);\n  } else throw e;\n}","preventionTips":["Validate both halves of 'from ... to ...' strings with chrono-node","Default missing end dates to the current date instead of sending empty strings","Use ISO date arrays for programmatic ranges","Keep end-date inputs in UIs constrained to date pickers, not free text"],"tags":["date-parsing","user-input","rest-api","validation"],"backgroundTag":"unparseable-date-string","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}