{"record":{"id":"80aca7b5820137d9","repo":"actualbudget/actual","slug":"path-error-tablename-table-does-not-exist","errorCode":null,"errorMessage":"Path error: ${tableName} table does not exist","messagePattern":"Path error: (.+?) table does not exist","errorType":"exception","errorClass":"CompileError","httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/aql/compiler.ts","lineNumber":85,"sourceCode":"  }\n  return fieldDesc;\n}\n\nfunction makePath(state, path) {\n  const { schema, paths } = state;\n\n  const parts = path.split('.');\n  if (parts.length < 2) {\n    throw new CompileError('Invalid path: ' + path);\n  }\n\n  const initialTable = parts[0];\n\n  const tableName = parts.slice(1).reduce((tableName, field) => {\n    const table = schema[tableName];\n\n    if (table == null) {\n      throw new CompileError(`Path error: ${tableName} table does not exist`);\n    }\n\n    if (!table[field] || table[field].ref == null) {\n      throw new CompileError(\n        `Field not joinable on table ${tableName}: \"${field}\"`,\n      );\n    }\n\n    return table[field].ref;\n  }, initialTable);\n\n  let joinTable;\n  const parentParts = parts.slice(0, -1);\n  if (parentParts.length === 1) {\n    joinTable = parentParts[0];\n  } else {\n    const parentPath = parentParts.join('.');\n    const parentDesc = paths.get(parentPath);","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/aql/compiler.ts#L67-L103","documentation":"While walking a dotted path, makePath (compiler.ts:81) reduces over each segment, looking up the current table in the schema. If the intermediate table name is not in the schema at all, this CompileError is thrown — the path references a table that does not exist.","triggerScenarios":"A path like 'payees.unknownthing.name' or a mistyped first segment reaching makePath via q('transactions').filter({ 'payeesX.name': 'foo' }) — actually triggered when the reduce lands on a tableName missing from schema, e.g. 'account.typo.name'.","commonSituations":"Typos in the table portion of a relationship path; using plural/singular forms that don't match the schema ('accounts.bank' vs correct relationship names); schema changes between versions removing a join table.","solutions":["Fix the table segment in the path to a valid schema table/relationship name (see aql schema.ts).","Use the documented relationship names: e.g. on transactions use 'payee.name', 'account.name', 'category.name'.","Verify the first path segment is the base table name as defined in the query state, and subsequent segments are joinable refs."],"exampleFix":"// before\nq('transactions').select('payees.name')\n// after\nq('transactions').select('payee.name')","handlingStrategy":"validation","validationCode":"import { schema } from './aql/schema';\nfunction assertPathTables(path) {\n  const parts = path.split('.');\n  let t = parts[0];\n  for (const f of parts.slice(1)) {\n    if (!schema[t]) throw new Error(`Unknown table ${t} in path ${path}`);\n    t = schema[t][f]?.ref;\n  }\n}","typeGuard":"function tableExists(name) {\n  return Object.prototype.hasOwnProperty.call(schema, name);\n}","tryCatchPattern":"try {\n  runQuery(q);\n} catch (e) {\n  if (e.message.includes('table does not exist')) {\n    throw new Error('Check the relationship name in your field path');\n  } else throw e;\n}","preventionTips":["Use the documented relationship names (payee, account, category) on transactions","Verify singular/plural naming against the schema before composing paths","Pin and test against the Actual version you deploy with"],"tags":["aql","query","path","schema","compile-error"],"backgroundTag":"unknown-table-in-path","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}