actualbudget/actual · error · CompileError

Casting string fields to dates is not supported

Error message

Casting string fields to dates is not supported

What it means

castInput (compiler.ts:264) can auto-cast only literal strings into dates. If the expression is a non-literal string (e.g. a string column/field reference), the compiler cannot convert it at compile time, so it throws this CompileError — string fields must be transformed explicitly, not implicitly cast.

Source

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

    return typed(expr.value, type);
  } else if (expr.type === 'null') {
    if (!expr.literal) {
      throw new CompileError("A non-literal null doesn't make sense");
    }

    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`);
    }

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Use $transform with $date/$datemachine-style functions to explicitly convert the string field before date comparison.
  2. Ensure the value being compared is a literal date string (auto-parsed) or a genuine date field, not a raw string column.
  3. If the column holds machine dates, compare it as a string/date-machinable value rather than forcing a date cast.

Example fix

// before
.filter({ imported_date: { $gte: '2024-01-01' } }) // imported_date is a string field in a date op
// after
.transform({ imported_date: { $date: '$imported_date' } })
 .filter({ imported_date: { $gte: '2024-01-01' } })
Defensive patterns

Strategy: validation

Validate before calling

function assertDateComparable(expr) {
  // only literal strings or date-typed fields may take part in date comparisons
  if (expr.kind === 'field' && expr.type === 'string') {
    throw new Error('Convert string field with $transform/$date before date comparison');
  }
}

Type guard

function isDateTyped(fieldDesc) {
  return fieldDesc != null && (fieldDesc.type === 'date' || String(fieldDesc.type).startsWith('date-'));
}

Try / catch

try {
  runQuery(q);
} catch (e) {
  if (e.message.includes('Casting string fields to dates is not supported')) {
    throw new Error('Transform the string field to a date explicitly first');
  } else throw e;
}

Prevention

When it happens

Trigger: Comparing a string field to a date in a filter where the string side is a field reference rather than a literal, e.g. building expressions where a non-literal string expr is used where a date type is required.

Common situations: Queries comparing two columns of mismatched types (string field vs date field); custom rules/reports referencing string columns inside date functions; migration of queries after type checking tightened.

Related errors


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