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

  1. 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.
  2. If building queries dynamically, validate field names are strings before composing the query.
  3. 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

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


AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29). Data as JSON: /api/errors/f24070a4b3461a36. Report an issue: GitHub.