cube-js/cube · error · UserError

Can't parse date: '${to}'

Error message

Can't parse date: '${to}'

What it means

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.

Source

Thrown at packages/cubejs-api-gateway/src/date-parser.js:81

    momentRange = [
      moment.tz(timezone).startOf('day').add(1, 'day'),
      moment.tz(timezone).endOf('day').add(1, 'day')
    ];
  } else if (dateString.match(/^from (.*) to (.*)$/)) {
    let [, from, to] = dateString.match(/^from(.{0,50})to(.{0,50})$/);
    from = from.trim();
    to = to.trim();

    const current = moment(now).tz(timezone);
    const fromResults = parse(from.trim(), new Date(current.format(moment.HTML5_FMT.DATETIME_LOCAL_MS)));
    const toResults = parse(to.trim(), new Date(current.format(moment.HTML5_FMT.DATETIME_LOCAL_MS)));

    if (!Array.isArray(fromResults) || !fromResults.length) {
      throw new UserError(`Can't parse date: '${from}'`);
    }

    if (!Array.isArray(toResults) || !toResults.length) {
      throw new UserError(`Can't parse date: '${to}'`);
    }

    const exactGranularity = ['second', 'minute', 'hour'].find(g => dateString.indexOf(g) !== -1) || 'day';
    momentRange = [
      momentFromResult(fromResults[0].start, timezone),
      momentFromResult(toResults[0].start, timezone)
    ];

    momentRange = [momentRange[0].startOf(exactGranularity), momentRange[1].endOf(exactGranularity)];
  } else {
    const current = moment(now).tz(timezone);
    const results = parse(dateString, new Date(current.format(moment.HTML5_FMT.DATETIME_LOCAL_MS)));

    if (!results?.length) {
      throw new UserError(`Can't parse date: '${dateString}'`);
    }

    const exactGranularity = ['second', 'minute', 'hour'].find(g => dateString.indexOf(g) !== -1) || 'day';

View on GitHub (pinned to 7d981676b3)

Solutions

  1. Fix the string after 'to' (shown in the error) to a chrono-parseable date, e.g. 'to 2024-02-28' or 'to now'
  2. Use built-in relative ranges ('last month', 'today') or explicit ISO arrays ['2024-01-01','2024-01-31'] instead
  3. Validate the end date with chrono-node in the client before sending the query
  4. If the end date can be empty, substitute the current date server-side before calling the API

Example fix

// before
{ dateRange: ['from last week to till now'] }
// after
{ dateRange: ['from last week to now'] }
Defensive patterns

Strategy: validation

Validate before calling

import { parse } from 'chrono-node';
const m = range.match(/^from(.{0,50})to(.{0,50})$/i);
const to = m ? m[2].trim() : '';
if (!parse(to).length) throw new Error(`Invalid 'to' date in range: '${to}'`);

Type guard

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;

Try / catch

try {
  await cube.load({ ...query, dateRange: [from, to] });
} catch (e) {
  if (e instanceof Error && e.message.startsWith("Can't parse date:")) {
    console.error(`Invalid range end ${e.message}`);
  } else throw e;
}

Prevention

When it happens

Trigger: 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).

Common situations: 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 ...'.

Related errors


AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02). Data as JSON: /api/errors/3f92c29e3442abb5. Report an issue: GitHub.