actualbudget/actual · error · CompileError
Can't convert to
Error message
Can't convert ${expr.type} to ${type} What it means
Generic cast failure at the end of castInput: after all specific cast branches (date casts, id-from-string, integer-to-float, `any` passthrough) none applied, so the expression's type cannot be converted to the requested type. This catches combinations with no defined cast, e.g. boolean to float or array to id.
Solutions
- Pass the value already in the target type (e.g. number instead of string) for numeric casts
- Use a string for id/`date` targets — those are the castable string paths
- Unwrap single-element arrays and pass the scalar directly
- Adjust the function schema/type declaration if you control it so the argument type matches
Example fix
// before
q.filter({ amount: { $gt: '100' } })
// after
q.filter({ amount: { $gt: 100 } }) Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof value === 'string' && ['float','integer','boolean'].includes(targetType)) {
throw new Error(`Strings don't auto-cast to ${targetType}; convert first`);
} Type guard
function isCastable(value, targetType) {
const t = Array.isArray(value) ? 'array' : value === null ? 'null' : typeof value === 'object' ? (value instanceof Date ? 'date' : 'object') : typeof value;
const ok = {
id: ['string'], float: ['integer'], integer: [], boolean: [],
date: ['string'], 'date-month': ['string'], 'date-year': ['string'],
};
return t === targetType || (ok[targetType] || []).includes(t);
} Try / catch
try {
runQuery(query);
} catch (e) {
if (/Can't convert .* to /.test(e.message)) {
throw new Error('Type mismatch in query: convert the value to the target type before querying', { cause: e });
}
throw e;
} Prevention
- Supply values in the exact target type (numbers for numeric comparisons)
- Know the limited cast table: string->id, integer->float, string->date family, any passthrough
- Unwrap arrays before passing scalars
When it happens
Trigger: Requesting a cast between unrelated types: e.g. string to float (strings don't auto-cast to numeric), boolean to date/id, array to any scalar type, date to id. Triggered via val(), compileFunction(), compileOp() when the function schema requires a type the argument can't supply.
Common situations: Passing numeric values as strings ('100' where 100 is needed); passing an array where a scalar is required ($in misuse with nested arrays); custom functions declaring parameter types the caller can't satisfy.
Related errors
- Can't cast to date
- Can't cast to date-month
- Can't cast to date-year
- Invalid field " ", are you trying to select a function? You…
- Invalid field reference:
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/f5826663be4b3a4a.
Report an issue: GitHub.
Appendix: source
Thrown at packages/loot-core/src/server/aql/compiler.ts:339
`CAST(SUBSTR(${expr2.value}, 1, 4) AS integer)`,
'date-year',
);
}
} else if (type === 'id') {
if (expr.type === 'string') {
return typed(expr.value, 'id', { literal: expr.literal });
}
} else if (type === 'float') {
if (expr.type === 'integer') {
return typed(expr.value, 'float', { literal: expr.literal });
}
}
if (expr.type === 'any') {
return typed(expr.value, type, { literal: expr.literal });
}
throw new CompileError(`Can't convert ${expr.type} to ${type}`);
}
// TODO: remove state from these functions
function val(state, expr, type?: string) {
let castedExpr = expr;
// Cast the type if necessary
if (type) {
castedExpr = castInput(state, expr, type);
}
if (castedExpr.literal) {
if (castedExpr.type === 'id') {
return `'${castedExpr.value}'`;
} else if (castedExpr.type === 'string') {
// Escape quotes
const value = castedExpr.value.replace(/'/g, "''");
return `'${value}'`;View on GitHub (pinned to d4334cb6e6)