actualbudget/actual · error

Invalid date:

Error message

Invalid date: 

What it means

For `date`-typed columns, convertInputType accepts only a Date object or a strict `YYYY-MM-DD` string that is also >= 1995-01-01. Anything else (malformed strings, timestamps, month-only strings) is rejected with 'Invalid date: <value>'. This protects the day-based date storage representation (toDateRepr) from invalid input.

Source

Thrown at packages/loot-core/src/server/aql/schema-helpers.ts:30

  if (value === undefined) {
    throw new Error('Query value cannot be undefined');
  } else if (value === null) {
    if (type === 'boolean') {
      return 0;
    }

    return null;
  }

  switch (type) {
    case 'date':
      if (value instanceof Date) {
        return toDateRepr(dayFromDate(value));
      } else if (
        value.match(/^\d{4}-\d{2}-\d{2}$/) == null ||
        value < '1995-01-01'
      ) {
        throw new Error('Invalid date: ' + value);
      }

      return toDateRepr(value);
    case 'date-month':
      return toDateRepr(value.slice(0, 7));
    case 'date-year':
      return toDateRepr(value.slice(0, 4));
    case 'boolean':
      return value ? 1 : 0;
    case 'id':
      if (typeof value !== 'string' && value !== null) {
        throw new Error('Invalid id, must be string: ' + value);
      }
      return value;
    case 'integer':
      if (typeof value === 'number' && Number.isInteger(value)) {
        return value;
      } else {

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Normalize the value to a YYYY-MM-DD day string before querying (e.g. slice an ISO timestamp: iso.slice(0, 10)).
  2. Use the shared `dayFromDate` util to convert a Date object instead of formatting by hand.
  3. Use the `date-month` or `date-year` field types if you actually have coarser-grained dates.
  4. Check for dates earlier than 1995-01-01 and handle them explicitly (clamp or reject in your own code).

Example fix

// before
q('transactions').insert({ date: '2024-06-01T12:00:00Z' });
// after
q('transactions').insert({ date: dayFromDate(new Date('2024-06-01T12:00:00Z')) });
Defensive patterns

Strategy: validation

Validate before calling

const isDayStr = (v) => typeof v === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(v) && v >= '1995-01-01';

Type guard

function isQueryDate(v) {
  if (v instanceof Date) return true;
  return typeof v === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(v) && v >= '1995-01-01';
}

Try / catch

try {
  return await runQuery(q.filter({ date }));
} catch (e) {
  if (e.message.startsWith('Invalid date:')) {
    logger.warn('Falling back: bad date input', { date });
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing a full ISO timestamp ('2024-01-01T10:00:00Z'), a numeric epoch, an empty string, a 'YYYY-MM' string into a `date` field, or a valid-format date earlier than 1995-01-01 into an aql query param.

Common situations: Feeding values from third-party APIs (full ISO timestamps) directly into transactions.date, using Date.now() output instead of formatted day strings, or importing historical data predating 1995.

Related errors


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