actualbudget/actual · error · CompileError
Can't convert ${expr.type} to ${type}
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.
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)
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 ${expr.type} to date
- Can't cast ${expr.type} to date-month
- Can't cast ${expr.type} to date-year
- Table "${tableName}" does not exist in the schema
- Too few arguments
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/f5826663be4b3a4a.
Report an issue: GitHub.