actualbudget/actual · error · CompileError
Unsupported type of expression:
Error message
Unsupported type of expression:
What it means
compileLiteral accepts only null, Date, string, boolean, number, and array literals. Anything else (plain objects, functions, symbols, BigInt) throws 'Unsupported type of expression: ' + JSON.stringify(value). The compiler has no SQL representation for it.
Source
Thrown at packages/loot-core/src/server/aql/compiler.ts:481
} else if (value === null) {
return typed('NULL', 'null', { literal: true });
} else if (value instanceof Date) {
return typed(nativeDateToInt(value), 'date', { literal: true });
} else if (typeof value === 'string') {
// Allow user to escape $, and quote the string to make it a
// string literal in the output
value = value.replace(/\\\$/g, '$');
return typed(value, 'string', { literal: true });
} else if (typeof value === 'boolean') {
return typed(value ? 1 : 0, 'boolean', { literal: true });
} else if (typeof value === 'number') {
return typed(value, Number.isInteger(value) ? 'integer' : 'float', {
literal: true,
});
} else if (Array.isArray(value)) {
return typed(value, 'array', { literal: true });
} else {
throw new CompileError(
'Unsupported type of expression: ' + JSON.stringify(value),
);
}
}
const compileExpr = saveStack('expr', (state, expr) => {
if (typeof expr === 'string') {
// Field reference
if (expr[0] === '$') {
const fieldRef = expr === '$' ? state.implicitField : expr.slice(1);
if (fieldRef == null || fieldRef === '') {
throw new CompileError('Invalid field reference: ' + expr);
}
return transformField(state, fieldRef);
}
View on GitHub (pinned to d4334cb6e6)
Solutions
- Convert the value to a supported literal: primitive string/number/boolean, null, native Date, or array
- Call .toDate() on dayjs/moment wrappers before passing them
- Use the proper operator-expression syntax ($gte etc.) instead of a bare object where a literal is expected
- Stringify/serialize custom objects yourself before embedding them
Example fix
// before
q.filter({ date: dayjs('2024-01-15') })
// after
q.filter({ date: dayjs('2024-01-15').toDate() }) Defensive patterns
Strategy: type-guard
Validate before calling
const SUPPORTED = ['string','number','boolean'];
function assertLiteral(v) {
if (v == null || v instanceof Date || Array.isArray(v) || SUPPORTED.includes(typeof v)) return;
throw new Error('Unsupported query literal: ' + typeof v);
} Type guard
function isSupportedLiteral(v) {
return v == null || v instanceof Date || Array.isArray(v) ||
['string','number','boolean'].includes(typeof v);
} Try / catch
try {
runQuery(query);
} catch (e) {
if (/Unsupported type of expression/.test(e.message)) {
console.error('Convert the value to a supported literal (primitive, Date, array, null)');
}
throw e;
} Prevention
- Call .toDate() on dayjs/moment objects before embedding
- Use operator syntax ($gte, etc.) for structured comparisons, not bare objects
- Never embed functions, class instances, or Symbols in queries
When it happens
Trigger: Passing a nested plain object as a literal value (e.g. { date: { gte: '2024-01' } } in a position expecting a raw literal rather than an operator expression); passing a function or class instance; passing Symbol/BigInt.
Common situations: Mixing up operator-object syntax ({ $gte: ... }) with raw literal positions; passing Date-like wrappers (dayjs/moment objects) that aren't real Date instances; serializing errors into query values.
Related errors
- `undefined` is not a valid query value
- Table "${tableName}" does not exist in the schema
- Can't cast ${expr.type} to date
- Can't cast ${expr.type} to date-month
- Can't cast ${expr.type} to date-year
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/e51c880ed5429a0f.
Report an issue: GitHub.