actualbudget/actual · error · CompileError
This function cannot track error data. It needs to accept th
Error message
This function cannot track error data. It needs to accept the compiler state as the first argument.
What it means
saveStack wraps compiler functions so errors can report the failing expression via state.compileStack. If a wrapped function is invoked without a compiler state (or one lacking compileStack) as its first argument, the compiler throws this CompileError — it's an internal contract violation, usually caused by calling a compiled function directly instead of through the normal compilation path.
Source
Thrown at packages/loot-core/src/server/aql/compiler.ts:386
function validateArgLength(arr: unknown[], min: number, max?: number) {
if (max == null) {
max = min;
}
if (min != null && arr.length < min) {
throw new CompileError('Too few arguments');
}
if (max != null && arr.length > max) {
throw new CompileError('Too many arguments');
}
}
//// Nice errors
function saveStack(type, func) {
return (state, ...args) => {
if (state == null || state.compileStack == null) {
throw new CompileError(
'This function cannot track error data. ' +
'It needs to accept the compiler state as the first argument.',
);
}
state.compileStack.push({ type, args });
const ret = func(state, ...args);
state.compileStack.pop();
return ret;
};
}
function prettyValue(value) {
if (typeof value === 'string') {
return value;
} else if (value === undefined) {
return 'undefined';
}View on GitHub (pinned to d4334cb6e6)
Solutions
- Always pass the compiler state as the first argument when invoking these functions
- Route query compilation through the public compileQuery/aql API instead of internal functions
- If adding a custom op/function, register it so the normal saveStack-wrapped path runs with a valid state
- Initialize a proper state object (including compileStack) in test harnesses that call compiler internals
Example fix
// before compileExpr(null, expr) // after const state = makeCompilerState(schema); // includes compileStack: [] compileExpr(state, expr)
Defensive patterns
Strategy: try-catch
Validate before calling
function assertCompilerState(state) {
if (state == null || state.compileStack == null) {
throw new Error('Compiler functions require a state with compileStack as first arg');
}
} Type guard
function hasCompilerState(args) {
return args.length > 0 && args[0] != null && Array.isArray(args[0].compileStack);
} Try / catch
try {
return compileExpr(state, expr);
} catch (e) {
if (/cannot track error data/.test(e.message)) {
throw new Error('Internal misuse: pass the compiler state as first argument or use the public aql API', { cause: e });
}
throw e;
} Prevention
- Don't call internal compiler functions directly; use the public aql API
- Always thread `state` as the first argument in custom ops
- Keep compileStack initialized when constructing test states
When it happens
Trigger: Calling a wrapped compiler function (compileExpr, compileFunction, compileOp, compileWhere, compileSelect, compileGroupBy) without a state object first argument, or with state=null; custom code reusing internal compiler functions with a wrong signature.
Common situations: Monkey-patching or extending the compiler with custom functions that don't thread `state`; calling internal APIs in tests without constructing a state; refactors that changed the argument order.
Related errors
- 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
- Can't convert ${expr.type} to ${type}
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/cca9479ea2709792.
Report an issue: GitHub.