{"record":{"id":"64f96c6b043b71a3","repo":"actualbudget/actual","slug":"invalid-internal-table-filter-field-names-cannot","errorCode":null,"errorMessage":"Invalid internal table filter: field names cannot contain paths","messagePattern":"Invalid internal table filter: field names cannot contain paths","errorType":"exception","errorClass":"CompileError","httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/aql/compiler.ts","lineNumber":1099,"sourceCode":"  const { withDead, validateRefs = true, tableOptions, rawMode } = queryState;\n\n  const {\n    tableViews = {},\n    tableFilters = () => [],\n    customizeQuery = queryState => queryState,\n  } = schemaConfig;\n\n  const internalTableFilters = name => {\n    const filters = tableFilters(name);\n    // These filters cannot join tables and must be simple strings\n    for (const filter of filters) {\n      if (Array.isArray(filter)) {\n        throw new CompileError(\n          'Invalid internal table filter: only object filters are supported',\n        );\n      }\n      if (Object.keys(filter)[0].indexOf('.') !== -1) {\n        throw new CompileError(\n          'Invalid internal table filter: field names cannot contain paths',\n        );\n      }\n    }\n    return filters;\n  };\n\n  const tableRef = (name: string, isJoin?: boolean) => {\n    const view =\n      typeof tableViews === 'function'\n        ? tableViews(name, { withDead, isJoin, tableOptions })\n        : tableViews[name];\n    return view || name;\n  };\n\n  const tableName = queryState.table;\n\n  const {","sourceCodeStart":1081,"sourceCodeEnd":1117,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/aql/compiler.ts#L1081-L1117","documentation":"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.","triggerScenarios":"Registering an internal table filter like `{'payee.name': 'foo'}` in the tableFilters mapping for an internal table, or programmatically building nested-path filter keys.","commonSituations":"Trying to constrain internal tables by related-table fields, or copying filter objects built for normal queries (which allow paths) into tableFilters.","solutions":["Flatten the filter to a direct column of the internal table (e.g. `payee` id instead of `payee.name`).","Perform the path-based constraint in the main query conditions rather than in tableFilters.","Denormalize the needed value onto the internal table at write time if the constraint is always required."],"exampleFix":"// before\n{ 'account.name': 'Checking' }\n// after\n{ account: checkingAccountId }","handlingStrategy":"validation","validationCode":"function assertNoPathFilters(filters) {\n  for (const f of filters) {\n    for (const key of Object.keys(f)) {\n      if (key.includes('.')) throw new Error(`Internal table filter key cannot contain a path: ${key}`);\n    }\n  }\n}","typeGuard":"const isPlainColumnFilter = (f) => typeof f === 'object' && f !== null && !Array.isArray(f) && Object.keys(f).every(k => !k.includes('.'));","tryCatchPattern":null,"preventionTips":["Filter internal tables only by their own columns.","Move related-table constraints into the query's filter clause.","Reject dotted keys when building filters programmatically."],"tags":["aql","schema","internal-table-filters"],"backgroundTag":"invalid-table-filter","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}