actualbudget/actual · error

Field "${field}" does not exist on table ${table}: ${JSON.st

Error message

Field "${field}" does not exist on table ${table}: ${JSON.stringify(obj)}

What it means

conform rejects any field in the input object that is not declared in the table's schema (fields starting with '_' are exempt and ignored). This prevents accidentally writing unexpected columns to the database, and the error includes the whole object to aid debugging.

Source

Thrown at packages/loot-core/src/server/aql/schema-helpers.ts:120

  // Rename fields if necessary
  const fieldRef = field => {
    if (views[table] && views[table].fields) {
      return views[table].fields[field] || field;
    }
    return field;
  };

  return Object.fromEntries(
    Object.keys(obj)
      .map(field => {
        // Fields that start with an underscore are ignored
        if (field[0] === '_') {
          return null;
        }

        const fieldDesc = tableSchema[field];
        if (fieldDesc == null) {
          throw new Error(
            `Field "${field}" does not exist on table ${table}: ${JSON.stringify(
              obj,
            )}`,
          );
        }

        if (isRequired(field, fieldDesc) && obj[field] == null) {
          throw new Error(
            `"${field}" is required for table "${table}": ${JSON.stringify(
              obj,
            )}`,
          );
        }

        // treat undefined as missing
        if (obj[field] === undefined) {
          return null;
        }

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Strip unknown fields before calling: build the object from only the known schema fields.
  2. Prefix internal/metadata keys with '_' so conform ignores them.
  3. Fix the field name typo or update to the renamed schema field.
  4. Check the table schema for the exact accepted field names before constructing the object.

Example fix

// before
convertForInsert(schema, schemaConfig, 'transactions', { ...txn, payeeName: 'X' });
// after
const { payeeName, ...valid } = txn;
convertForInsert(schema, schemaConfig, 'transactions', valid);
Defensive patterns

Strategy: validation

Validate before calling

function pickSchemaFields(obj, tableSchema) {
  return Object.fromEntries(
    Object.entries(obj).filter(([k]) => k.startsWith('_') || tableSchema[k] != null),
  );
}

Try / catch

try {
  return convertForUpdate(schema, schemaConfig, table, obj);
} catch (e) {
  if (e.message.includes('does not exist on table')) {
    logger.error('Unknown field passed to update', { obj });
    // strip unknown fields and retry, or rethrow
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing an object to insert/update/query building that contains extra keys — e.g. a raw API response, a joined row, or renamed fields — into convertForInsert/convertForUpdate for a table where those keys are not in the schema.

Common situations: Spreading fetched records (with metadata like 'tombstone' variants or computed fields) straight into inserts, schema migrations renaming a column while old call sites still use the old field name, and typos in field names ('amout' vs 'amount').

Related errors


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