{"record":{"id":"70128d48d3a8589e","repo":"actualbudget/actual","slug":"invalid-path-path","errorCode":null,"errorMessage":"Invalid path: ${path}","messagePattern":"Invalid path: (.+?)","errorType":"exception","errorClass":"CompileError","httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/aql/compiler.ts","lineNumber":76,"sourceCode":"  if (schema[tableName] == null) {\n    throw new CompileError(`Table \"${tableName}\" does not exist in the schema`);\n  }\n\n  const fieldDesc = schema[tableName][field];\n  if (fieldDesc == null) {\n    throw new CompileError(\n      `Field \"${field}\" does not exist in table \"${tableName}\"`,\n    );\n  }\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;","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/aql/compiler.ts#L58-L94","documentation":"makePath (compiler.ts:71) resolves a dotted relationship path used by AQL field references. A valid path must contain at least a table and a field (e.g. 'payee.name'). If the path has fewer than two dot-separated parts, the compiler cannot form a join and throws this CompileError.","triggerScenarios":"Calling resolvePath/transformField with a bare table name such as q('transactions').select('payee') or filter({ 'account': ... }) — a single segment with no '.field' part.","commonSituations":"Passing a relationship/table name instead of 'relation.field'; dynamically building field strings and ending up with just the prefix; copy-pasting a path and dropping the '.field' suffix; rules or reports configured with an incomplete field path.","solutions":["Append the field name to the path: use 'payee.name' instead of 'payee'.","If you want the raw id column of the implicit table, use an unqualified field like 'id' (no path) rather than a one-part path.","Inspect the dynamic code that builds the field string and ensure it always produces at least 'table.field'."],"exampleFix":"// before\nq('transactions').select('payee')\n// after\nq('transactions').select('payee.name')","handlingStrategy":"validation","validationCode":"function assertPath(path) {\n  if (typeof path !== 'string' || path.split('.').length < 2) {\n    throw new Error(`Field path must be \"table.field\": got ${path}`);\n  }\n}\nassertPath('payee.name');","typeGuard":"function isFieldPath(v) {\n  return typeof v === 'string' && /^[A-Za-z_][\\w]*\\.[A-Za-z_][\\w]*$/.test(v);\n}","tryCatchPattern":"try {\n  runQuery(q);\n} catch (e) {\n  if (String(e.message).startsWith('Invalid path:')) {\n    console.warn('Dotted field path required, e.g. payee.name');\n  } else throw e;\n}","preventionTips":["Always write relationship references as relation.field","Validate dynamically built field strings end with a field segment","Add unit tests for query builders that interpolate field names"],"tags":["aql","query","path","compile-error"],"backgroundTag":"invalid-aql-path","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}