actualbudget/actual · error · CompileError

Table "${tableName}" does not exist in the schema

Error message

Table "${tableName}" does not exist in the schema

What it means

Actual's AQL query compiler resolves every table referenced in a query against the supplied schema catalog. getFieldDescription looks up schema[tableName]; when the table is absent from the schema object it throws CompileError with this message. This guards against querying tables that don't exist (or aren't exposed to AQL) before any SQL is generated.

Source

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

  const parts = path.split('.');
  return { path: parts.slice(0, -1).join('.'), field: parts[parts.length - 1] };
}

function isKeyword(str) {
  return str === 'group';
}

export function quoteAlias(alias) {
  return alias.indexOf('.') === -1 && !isKeyword(alias) ? alias : `"${alias}"`;
}

function typed(value, type, { literal = false } = {}) {
  return { value, type, literal };
}

function getFieldDescription(schema, tableName, field) {
  if (schema[tableName] == null) {
    throw new CompileError(`Table "${tableName}" does not exist in the schema`);
  }

  const fieldDesc = schema[tableName][field];
  if (fieldDesc == null) {
    throw new CompileError(
      `Field "${field}" does not exist in table "${tableName}"`,
    );
  }
  return fieldDesc;
}

function makePath(state, path) {
  const { schema, paths } = state;

  const parts = path.split('.');
  if (parts.length < 2) {
    throw new CompileError('Invalid path: ' + path);
  }

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Correct the table name in the query to one present in the schema (transactions, accounts, payees, categories, category_groups, rules, schedules, etc.).
  2. Check the schema map in packages/loot-core/src/server/aql/schema.ts for the exact exposed table names.
  3. If the table was renamed in a newer Actual version, update the query to the new name.
  4. For dynamic queries, validate the table name against Object.keys(schema) before building the query.

Example fix

// before
const q = aql.query('transations').select('*');
// after
const q = aql.query('transactions').select('*');
Defensive patterns

Strategy: validation

Validate before calling

import { schema } from '../server/aql/schema';
function tableExists(name) {
  return Object.prototype.hasOwnProperty.call(schema, name);
}
if (!tableExists(tableName)) throw new Error(`unknown AQL table: ${tableName}`);

Type guard

function isAqlTable(name) {
  return typeof name === 'string' && name in schema;
}

Try / catch

import { CompileError } from '../server/aql/compiler';
try {
  const { data } = await aql.runQuery(q);
} catch (e) {
  if (e instanceof CompileError && e.message.includes('does not exist in the schema')) {
    logger.error({ table: e.message }, 'fix table name in query');
  } else throw e;
}

Prevention

When it happens

Trigger: Running aquery (loot-core's aql.runQuery / Query class) whose from()/table name is misspelled or not part of the schema — e.g. q('transations') instead of q('transactions'), or a custom/internal table name not registered in the schema map passed to the compiler via fieldDesc.

Common situations: Typo in a custom query built with the aql query builder; using an internal-only or deprecated table name after a schema rename between Actual versions; API/plugin code (actual-js) referencing tables the AQL layer doesn't expose; dynamically constructed table names built from user input.

Related errors


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