actualbudget/actual · error · CompileError

Can't cast ${expr.type} to date

Error message

Can't cast ${expr.type} to date

What it means

castInput is asked to coerce a query expression to the `date` type, but the expression's type is not `date`, a string literal, a parameter, null, or `any` — the only castable source types. The compiler throws CompileError naming the offending source type. Only literal strings can be parsed into dates; typed fields like integers or booleans cannot.

Source

Thrown at packages/loot-core/src/server/aql/compiler.ts:275

    if (type === 'boolean') {
      return typed(0, 'boolean', { literal: true });
    }
    return expr;
  }

  // These are all things that can be safely casted automatically
  if (type === 'date') {
    if (expr.type === 'string') {
      if (expr.literal) {
        return parseDate(expr.value) || badDateFormat(expr.value, 'date');
      } else {
        throw new CompileError(
          'Casting string fields to dates is not supported',
        );
      }
    }

    throw new CompileError(`Can't cast ${expr.type} to date`);
  } else if (type === 'date-month') {
    let expr2;
    if (expr.type === 'date') {
      expr2 = expr;
    } else if (expr.type === 'string' || expr.type === 'any') {
      expr2 =
        parseMonth(expr.value) ||
        parseDate(expr.value) ||
        badDateFormat(expr.value, 'date-month');
    } else {
      throw new CompileError(`Can't cast ${expr.type} to date-month`);
    }

    if (expr2.literal) {
      return typed(
        dateToInt(expr2.value.toString().slice(0, 6)),
        'date-month',
        { literal: true },

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Pass a value that is already a date-typed field or a date-parseable string literal (e.g. '2024-01-15')
  2. Check the field reference — you likely named a non-date column; use `date` instead
  3. Cast on your side first: convert the value to a 'YYYY-MM-DD' string before putting it in the query
  4. Remove the wrong argument from the date-typed function call and supply the correct date expression

Example fix

// before
q.filter({ date: { $gte: q('amount') } })
// after
q.filter({ date: { $gte: '2024-01-15' } })
Defensive patterns

Strategy: validation

Validate before calling

const DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
if (!(typeof v === 'string' && DATE_RE.test(v))) {
  throw new Error('Expected YYYY-MM-DD date string, got: ' + typeof v);
}

Type guard

function isDateLike(v) {
  return typeof v === 'string' && /^\d{4}-\d{2}-\d{2}/.test(v);
}

Try / catch

try {
  runQuery(q.filter({ date: { $gte: input } }));
} catch (e) {
  if (/Can't cast .* to date/.test(e.message)) {
    throw new Error(`Bad date input: ${JSON.stringify(input)}`, { cause: e });
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling a query function/op whose schema declares a `date` argument while passing a value of another type, e.g. `date` (integer month index), `boolean`, `id`, `array`, or a non-literal string field. Reached via val(), compileFunction(), or compileOp() during query compilation.

Common situations: Passing an integer or amount field where a date is expected (e.g. comparing a transaction amount column to a date); passing a Date object already compiled to another type; mixing up field names so a non-date column lands in a date filter.

Related errors


AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29). Data as JSON: /api/errors/67ef0135280d99c3. Report an issue: GitHub.