cube-js/cube · error · UserError
Your cron string ('${every}') is correct, but we support onl
Error message
Your cron string ('${every}') is correct, but we support only equal time intervals. What it means
Cube only supports cron strings that represent EQUAL time intervals (a restricted pattern like '*|d h *|m * * *|s'). The cron must parse correctly, but also match this restricted regex; otherwise this UserError is thrown even though the cron is technically valid.
Source
Thrown at packages/cubejs-schema-compiler/src/adapter/BaseQuery.js:4887
end: interval.next(),
dayOffset: dayOffset / 1000, // Convert from ms to seconds
};
} catch (err) {
throw new UserError(`Invalid cron string '${every}' in refreshKey (${err})`);
}
}
calcIntervalForCronString(refreshKey) {
const every = refreshKey.every || '1 hour';
const { start, end, dayOffset } = this.parseCronSyntax(every);
const interval = (end.getTime() - start.getTime()) / 1000;
if (
!/^(\*|\d+)? ?(\*|\d+) (\*|\d+) \* \* (\*|\d+)$/g.test(every.replace(/ +/g, ' ').replace(/^ | $/g, ''))
) {
throw new UserError(`Your cron string ('${every}') is correct, but we support only equal time intervals.`);
}
let utcOffset = 0;
if (refreshKey.timezone || this.timezone) {
utcOffset = moment.tz(refreshKey.timezone).utcOffset() * 60;
}
return {
utcOffset,
interval,
dayOffset,
};
}
/**
* Both the rendered SQL and the descriptor handed to the orchestrator for local
* evaluation derive from this, so they cannot disagree on the formula.View on GitHub (pinned to 7d981676b3)
Solutions
- Simplify the cron to an equal interval pattern (one specific or wildcard value per field), e.g. '0 */4 * * *'
- Prefer the simple interval form: every: '4 hours'
- Split complex schedules into multiple pre-aggregations each with an equal-interval refreshKey
Example fix
// before
refreshKey: { every: '0 0 1,15 * *' }
// after
refreshKey: { every: '1 day' } Defensive patterns
Strategy: validation
Validate before calling
const EQUAL_CRON = /^(\*|\d+)? ?(\*|\d+) (\*|\d+) \* \* (\*|\d+)$/;
function validateEqualCron(every) {
const norm = every.replace(/ +/g, ' ').replace(/^ | $/g, '');
if (!EQUAL_CRON.test(norm)) throw new Error(`Cron must be an equal interval: ${every}`);
} Type guard
const isEqualIntervalCron = (s) => /^(\*|\d+)? ?(\*|\d+) (\*|\d+) \* \* (\*|\d+)$/.test(String(s).replace(/ +/g,' ').replace(/^ | $/g,''));
Try / catch
try { await cubeApi.query(q); } catch (e) { if (/support only equal time intervals/.test(e.message)) console.error('Simplify cron to an equal interval or use every: "n unit"'); throw e; } Prevention
- Avoid cron lists/ranges (commas, dashes) in refreshKey
- Use 'every: "n hours"' form instead of cron for uniform intervals
- Pre-aggregation refresh schedules must be periodic — model complex schedules with multiple pre-aggs
When it happens
Trigger: refreshKey with a valid cron expression whose fields are not a single equal interval, e.g. '0 0 1,15 * *' (two days a month) or '0 30 2 * *' combined with hour wildcards — anything failing the regex /^(\*|\d+)? ?(\*|\d+) (\*|\d+) \* \* (\*|\d+)$/ after whitespace normalization.
Common situations: Using cron lists/ranges (1,15 or 1-5) hoping for arbitrary schedules; a cron that is valid for standard cron but too complex for Cube's interval-based refresh; migrating an existing crontab entry directly.
Related errors
- Invalid cron string '${every}' in refreshKey (${err})
- Invalid interval: ${interval}
- Can't parse date: '${from}'
- Can't parse date: '${to}'
- Can't parse date: '${dateString}'
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/5e752a51a062b8a5.
Report an issue: GitHub.