cube-js/cube · error

Athena/Presto supports only simple intervals with one date p

Error message

Athena/Presto supports only simple intervals with one date part

What it means

PrestoDB/Athena only supports date_bin-style shifting with a single-unit interval (e.g. '1 day', '5 minute'). parseSqlInterval() returns an object of date parts; if more than one part is present (e.g. '1 month 3 days'), the query cannot be translated, so Cube throws immediately in dateBin.

Source

Thrown at packages/cubejs-schema-compiler/src/adapter/PrestodbQuery.ts:95

    const timestampField = this.promoteDateToTimestamp(field);
    const atTimezone = `${timestampField} AT TIME ZONE '${this.timezone}'`;
    return `CAST(date_add('minute', timezone_minute(${atTimezone}), date_add('hour', timezone_hour(${atTimezone}), ${timestampField})) AS TIMESTAMP)`;
  }

  /**
   * Returns sql for source expression floored to timestamps aligned with
   * intervals relative to origin timestamp point.
   * Athena doesn't support INTERVALs directly — using date_diff/date_add.
   * Origin is wrapped in `CAST(... AS TIMESTAMP)` so that `date_add` returns
   * a plain TIMESTAMP rather than `timestamp with time zone` — Hive cannot
   * write the TZ-aware type into an export bucket.
   */
  public dateBin(interval: string, source: string, origin: string): string {
    const intervalParsed = parseSqlInterval(interval);
    const intervalParts = Object.entries(intervalParsed);

    if (intervalParts.length > 1) {
      throw new Error('Athena/Presto supports only simple intervals with one date part');
    }

    const [unit, count] = intervalParts[0];
    const originExpr = `CAST(${this.timeStampCast(`'${origin}'`)} AS TIMESTAMP)`;

    return `date_add('${unit}',
      floor(
        date_diff('${unit}', ${originExpr}, ${source}) / ${count}
      ) * ${count},
      ${originExpr}
    )`;
  }

  public timeGroupedColumn(granularity, dimension) {
    return `date_trunc('${GRANULARITY_TO_INTERVAL[granularity]}', ${dimension})`;
  }

  public intervalString(interval: string): string {

View on GitHub (pinned to 7d981676b3)

Solutions

  1. Use an interval with exactly one date part, e.g. change '1 month 3 days' to '1 month' or '3 days'
  2. If a compound interval is required, compute the equivalent single unit (e.g. 6 months) or split the logic into multiple granularities/pre-aggregations
  3. Check that the query is not accidentally routed to Presto/Athena (wrong driver/dbType) if your interval was valid on another database

Example fix

// before
const interval = '1 month 7 days';
queryBuilder.dateBin(interval, src, origin);
// after
const interval = '1 month'; // or '7 days' — one date part only
Defensive patterns

Strategy: validation

Validate before calling

const parts = parseSqlInterval(interval);
if (Object.values(parts).filter(v => v).length > 1) throw new Error('Use a single date-part interval for Athena/Presto');

Try / catch

try { return qb.dateBin(interval, src, origin); } catch (e) { if (e.message.includes('simple intervals')) { /* fall back to single-unit interval or rethrow with guidance */ } throw e; }

Prevention

When it happens

Trigger: Calling dateBin(interval, source, origin) (directly or via time-dimension dateBin/granularity derivation) with a compound interval string like '1 month 2 days' or '1 year 6 months' against a Presto/Athena data source.

Common situations: Defining a named granularity or pre-aggregation with a multi-part interval; a time dimension granularity configured for another dialect (e.g. Postgres supports compound intervals) being reused against Athena.

Related errors


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