actualbudget/actual · error · CompileError
Invalid field name, must be a string
Error message
Invalid field name, must be a string
What it means
transformField (compiler.ts:142) validates that every field reference passed to the compiler is a string. Dotted path strings are the only supported way to name fields; non-string values (numbers, objects, arrays) cannot be parsed into a path/field pair, so a CompileError is thrown immediately.
Source
Thrown at packages/loot-core/src/server/aql/compiler.ts:144
path: [...acc.path, fullName],
};
},
{ context: state.implicitTableName, path: [] },
).path;
paths.forEach(path => {
if (!state.paths.get(path)) {
state.paths.set(path, makePath(state, path));
}
});
const pathInfo = state.paths.get(paths[paths.length - 1]);
return pathInfo;
}
function transformField(state, name) {
if (typeof name !== 'string') {
throw new CompileError('Invalid field name, must be a string');
}
const { path, field: originalField } = popPath(name);
let field = originalField;
let pathInfo;
if (path === '') {
pathInfo = {
tableName: state.implicitTableName,
tableId: state.implicitTableId,
};
} else {
pathInfo = resolvePath(state, path);
}
const fieldDesc = getFieldDescription(
state.schema,
pathInfo.tableName,View on GitHub (pinned to d4334cb6e6)
Solutions
- Ensure the value passed to select/filter expressions is a string field name; convert with String(name) only if you're certain it's a name.
- If building queries dynamically, validate field names are strings before composing the query.
- For expressions, wrap values with q(expr) helpers so literal values are typed as literals rather than treated as field names.
Example fix
// before
q('transactions').select(someVar) // someVar = 42
// after
q('transactions').select('amount') Defensive patterns
Strategy: type-guard
Validate before calling
function assertStringField(name) {
if (typeof name !== 'string') {
throw new TypeError(`Field name must be a string, got ${typeof name}`);
}
} Type guard
function isFieldName(v) {
return typeof v === 'string' && v.length > 0;
} Try / catch
try {
runQuery(q);
} catch (e) {
if (e.message === 'Invalid field name, must be a string') {
throw new Error('Check that query fields are passed as strings');
} else throw e;
} Prevention
- Type query-building functions with TypeScript string types
- Sanitize user/config-driven field selections before building queries
- Use expression helpers for values instead of passing raw values as fields
When it happens
Trigger: q('transactions').select(123), select({ amount: 42 }) with a non-string value where a field name is expected, filter keys/values built from unvalidated user input, or passing a symbol/object instead of a field name string.
Common situations: Programmatic query building where field names come from variables, JSON configs, or API input; TypeScript-less code losing the intended string; refactors passing a field descriptor object where only its .name should go.
Related errors
- Field "${field}" does not exist in table "${tableName}"
- Invalid path: ${path}
- Path error: ${tableName} table does not exist
- Field not joinable on table ${tableName}: "${field}"
- Path does not exist:
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/f24070a4b3461a36.
Report an issue: GitHub.