actualbudget/actual · error · CompileError

Invalid internal table filter: field names cannot contain pa

Error message

Invalid internal table filter: field names cannot contain paths

What it means

Internal table filters must reference plain columns of the internal table only. Because these filters are compiled without join support, a filter key containing a dot (a path into a related table, e.g. `payee.name`) cannot be resolved and CompileError is thrown.

Source

Thrown at packages/loot-core/src/server/aql/compiler.ts:1099

  const { withDead, validateRefs = true, tableOptions, rawMode } = queryState;

  const {
    tableViews = {},
    tableFilters = () => [],
    customizeQuery = queryState => queryState,
  } = schemaConfig;

  const internalTableFilters = name => {
    const filters = tableFilters(name);
    // These filters cannot join tables and must be simple strings
    for (const filter of filters) {
      if (Array.isArray(filter)) {
        throw new CompileError(
          'Invalid internal table filter: only object filters are supported',
        );
      }
      if (Object.keys(filter)[0].indexOf('.') !== -1) {
        throw new CompileError(
          'Invalid internal table filter: field names cannot contain paths',
        );
      }
    }
    return filters;
  };

  const tableRef = (name: string, isJoin?: boolean) => {
    const view =
      typeof tableViews === 'function'
        ? tableViews(name, { withDead, isJoin, tableOptions })
        : tableViews[name];
    return view || name;
  };

  const tableName = queryState.table;

  const {

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Flatten the filter to a direct column of the internal table (e.g. `payee` id instead of `payee.name`).
  2. Perform the path-based constraint in the main query conditions rather than in tableFilters.
  3. Denormalize the needed value onto the internal table at write time if the constraint is always required.

Example fix

// before
{ 'account.name': 'Checking' }
// after
{ account: checkingAccountId }
Defensive patterns

Strategy: validation

Validate before calling

function assertNoPathFilters(filters) {
  for (const f of filters) {
    for (const key of Object.keys(f)) {
      if (key.includes('.')) throw new Error(`Internal table filter key cannot contain a path: ${key}`);
    }
  }
}

Type guard

const isPlainColumnFilter = (f) => typeof f === 'object' && f !== null && !Array.isArray(f) && Object.keys(f).every(k => !k.includes('.'));

Prevention

When it happens

Trigger: Registering an internal table filter like `{'payee.name': 'foo'}` in the tableFilters mapping for an internal table, or programmatically building nested-path filter keys.

Common situations: Trying to constrain internal tables by related-table fields, or copying filter objects built for normal queries (which allow paths) into tableFilters.

Related errors


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