{"record":{"id":"73de1fe2d41c360a","repo":"actualbudget/actual","slug":"field-is-required-for-table-table-jso","errorCode":null,"errorMessage":"\"${field}\" is required for table \"${table}\": ${JSON.stringify(obj)}","messagePattern":"\"(.+?)\" is required for table \"(.+?)\": (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/aql/schema-helpers.ts","lineNumber":128,"sourceCode":"  return Object.fromEntries(\n    Object.keys(obj)\n      .map(field => {\n        // Fields that start with an underscore are ignored\n        if (field[0] === '_') {\n          return null;\n        }\n\n        const fieldDesc = tableSchema[field];\n        if (fieldDesc == null) {\n          throw new Error(\n            `Field \"${field}\" does not exist on table ${table}: ${JSON.stringify(\n              obj,\n            )}`,\n          );\n        }\n\n        if (isRequired(field, fieldDesc) && obj[field] == null) {\n          throw new Error(\n            `\"${field}\" is required for table \"${table}\": ${JSON.stringify(\n              obj,\n            )}`,\n          );\n        }\n\n        // treat undefined as missing\n        if (obj[field] === undefined) {\n          return null;\n        }\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      })","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/aql/schema-helpers.ts#L110-L146","documentation":"conform enforces that required fields (those marked required in the schema, plus 'id') are present and non-null in the object being written. A required field that is null or undefined aborts the operation with a message naming the field, table, and full object.","triggerScenarios":"Calling convertForUpdate/conform with an object missing a required field such as a transaction's 'date' or 'account', or with that field explicitly set to null.","commonSituations":"Partial updates where the caller assumed only changed fields are needed but the required field was absent, import pipelines producing rows with null dates/accounts, and forms that allow submitting without selecting an account.","solutions":["Provide a valid value for the required field before writing.","For partial updates, merge with the existing record first: `{ ...existing, ...changes }`.","Validate input at your API/import boundary and reject incomplete rows with a clearer message.","If the field should not actually be required, update the schema definition (with care)."],"exampleFix":"// before\nconvertForUpdate(schema, schemaConfig, 'transactions', { id, amount }); // date missing\n// after\nconst existing = await getTransaction(id);\nconvertForUpdate(schema, schemaConfig, 'transactions', { ...existing, amount });","handlingStrategy":"validation","validationCode":"function requireFields(obj, fields) {\n  for (const f of fields) {\n    if (obj[f] == null) throw new Error(`Missing required field: ${f}`);\n  }\n}\nrequireFields(txn, ['id', 'account', 'date']);","typeGuard":null,"tryCatchPattern":"try {\n  return convertForUpdate(schema, schemaConfig, table, obj);\n} catch (e) {\n  if (e.message.includes('is required for table')) {\n    logger.error('Required field missing', { obj });\n    return { ok: false, reason: e.message };\n  }\n  throw e;\n}","preventionTips":["For partial updates, merge with the existing record first","Validate required fields at the import/API boundary","Read the table schema to know which fields are required"],"tags":["schema","required-field","validation","aql"],"backgroundTag":"required-field-missing","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}