{"record":{"id":"b35a16bf451990b1","repo":"actualbudget/actual","slug":"error-inserting-table-table-does-not-exist","errorCode":null,"errorMessage":"Error inserting: table \"${table}\" does not exist","messagePattern":"Error inserting: table \"(.+?)\" does not exist","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"packages/loot-core/src/server/aql/schema-helpers.ts","lineNumber":156,"sourceCode":"        }\n\n        // This option removes null values (see `convertForInsert`)\n        if (skipNull && obj[field] == null) {\n          return null;\n        }\n\n        return [fieldRef(field), convertInputType(obj[field], fieldDesc.type)];\n      })\n      .filter(Boolean),\n  );\n}\n\nexport function convertForInsert(schema, schemaConfig, table, rawObj) {\n  const obj = { ...rawObj };\n\n  const tableSchema = schema[table];\n  if (tableSchema == null) {\n    throw new Error(`Error inserting: table \"${table}\" does not exist`);\n  }\n\n  // Inserting checks all the fields in the table and adds any default\n  // values necessary\n  Object.keys(tableSchema).forEach(field => {\n    const fieldDesc = tableSchema[field];\n\n    if (obj[field] == null) {\n      if (fieldDesc.default !== undefined) {\n        obj[field] =\n          typeof fieldDesc.default === 'function'\n            ? fieldDesc.default()\n            : fieldDesc.default;\n      } else if (isRequired(field, fieldDesc)) {\n        // Although this check is also done in `conform`, it only\n        // checks the fields in `obj`. For insert, we need to do it\n        // here to check that all required fields in the table exist\n        throw new Error(","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/aql/schema-helpers.ts#L138-L174","documentation":"convertForInsert verifies the target table exists in the schema before iterating its fields to apply defaults. An unknown table during insert throws 'Error inserting: table \"X\" does not exist' — the insert-specific variant of the conform table check.","triggerScenarios":"Calling convertForInsert (directly or via insertWithSchema / toDb inside a transactor) with a table name that is misspelled, unregistered, or removed in the current schema version.","commonSituations":"Plugins/custom sync code written against old internal table names, copy-pasted insert code with a wrong table constant, and migrations that dropped or renamed a table without updating insert call sites.","solutions":["Correct the table name to a valid schema table ('transactions', 'accounts', etc.).","Grep the aql schema file for the exact registered table names.","If the table is new, add its schema definition before inserting.","Ensure the `schema` object passed into convertForInsert is the current full schema map, not a partial/stale copy."],"exampleFix":"// before\ninsertWithSchema('account', obj, {}); // wrong table\n// after\ninsertWithSchema('accounts', obj, {});","handlingStrategy":"validation","validationCode":"const VALID_INSERT_TABLES = new Set(Object.keys(schema));\nfunction safeInsert(table, obj) {\n  if (!VALID_INSERT_TABLES.has(table)) throw new Error(`Unknown insert table: ${table}`);\n  return insertWithSchema(table, obj, {});\n}","typeGuard":null,"tryCatchPattern":"try {\n  return insertWithSchema(table, obj, {});\n} catch (e) {\n  if (e.message.includes('Error inserting: table')) {\n    logger.error('Insert against unknown table', { table });\n    return null;\n  }\n  throw e;\n}","preventionTips":["Keep table names in a single constants module","Run integration tests for insert paths after schema upgrades","Avoid hand-writing table names in plugin/sync code"],"tags":["schema","insert","table","aql"],"backgroundTag":"unknown-table-schema","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}