{"record":{"id":"18fa04263f61a6ee","repo":"nocodb/nocodb","slug":"missing-required-columns-missingrequiredcol","errorCode":null,"errorMessage":"Missing required columns: ${[...missingRequiredColumns].join(', ')}","messagePattern":"Missing required columns: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/nc-gui/utils/dataUtils.ts","lineNumber":217,"sourceCode":"          o[childCol.title!] = ltarVal[relatedTableMeta!.columns!.find((c) => c.id === colOpt.fk_parent_column_id)!.title!]\n          if (o[childCol.title!] !== null && o[childCol.title!] !== undefined) missingRequiredColumns.delete(childCol.title)\n        }\n      }\n    }\n    // check all the required columns are not null\n    if (isColumnRequiredAndNull(col, row)) {\n      missingRequiredColumns.add(col.title)\n    }\n\n    if (!col.ai && (row?.[col.title as string] !== null || allowNullFieldIds.includes(col.id as string))) {\n      o[col.title as string] = row?.[col.title as string]\n    }\n\n    return o\n  }, Promise.resolve({}))\n\n  if (throwError && missingRequiredColumns.size) {\n    throw new Error(`Missing required columns: ${[...missingRequiredColumns].join(', ')}`)\n  }\n\n  return { missingRequiredColumns, insertObj }\n}\n\n// Relation types whose linked record can belong to only ONE parent record.\n// Copying such a link onto a duplicated record REASSIGNS the linked record to the\n// copy and silently detaches it from the original — a data-integrity hazard.\n//  - has-many / one-to-many: the related rows carry the FK pointing here, so\n//    copying moves those rows onto the duplicate.\n//  - one-to-one: a single record on each side, so copying steals it.\n// belongs-to / many-to-one own their own FK (the parent keeps its other children)\n// and many-to-many is additive, so those relationships copy safely.\nconst SINGLE_PARENT_RELATION_TYPES: RelationTypes[] = [\n  RelationTypes.HAS_MANY,\n  RelationTypes.ONE_TO_ONE,\n  RelationTypes.ONE_TO_MANY,\n]","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/nocodb/nocodb/blob/d3caaf4e890acf64bd49b788cf6dc32b7644c895/packages/nc-gui/utils/dataUtils.ts#L199-L235","documentation":"getDataInsertObj in dataUtils reduces the row over meta.columns and accumulates any required column whose value is null/empty into missingRequiredColumns. When throwError is true and that set is non-empty, it throws 'Missing required columns: <names>' so the caller knows the row violates NOT NULL constraints before any API insert.","triggerScenarios":"Inserting or duplicating a row where one or more required (NOT NULL, no default, non-auto-increment) columns were left empty, with throwError=true. Belongs-to relations whose FK is required also land in the set when the linked value is absent.","commonSituations":"Form submissions missing mandatory fields; duplication of a partial row; bulk paste/import that skips required columns; LTAR belongs-to fields not populated; columns whose rqd flag is true server-side.","solutions":["Pre-validate the row against meta.columns: fill or prompt for every required column before insert.","Call getDataInsertObj with throwError=false first to collect missingRequiredColumns and show inline field errors.","For duplicates, copy the source row's required values so the new row is never missing them.","Ensure belongs-to relations include a valid linked record when the FK column is required."],"exampleFix":"// before\nconst { insertObj } = await getDataInsertObj({ ...row, throwError: true })\n// after\nconst { missingRequiredColumns, insertObj } = await getDataInsertObj({ ...row, throwError: false })\nif (missingRequiredColumns.size) {\n  showFieldErrors([...missingRequiredColumns])\n  return\n}","handlingStrategy":"validation","validationCode":"// Run with throwError=false first to collect missing fields\nconst { missingRequiredColumns, insertObj } = await getDataInsertObj({ ...args, throwError: false })\nif (missingRequiredColumns.size) {\n  showFieldErrors([...missingRequiredColumns])\n  return\n}\nawait insertRow(insertObj)","typeGuard":"const rowSatisfiesRequired = (row: Record<string, any>, required: string[]): boolean =>\n  required.every((title) => row?.[title] !== undefined && row?.[title] !== null && row?.[title] !== '')","tryCatchPattern":"try {\n  await getDataInsertObj({ ...args, throwError: true })\n} catch (e) {\n  if ((e as Error).message.startsWith('Missing required columns:')) {\n    const missing = (e as Error).message.replace('Missing required columns: ', '').split(', ')\n    showFieldErrors(missing)\n  } else throw e\n}","preventionTips":["Pre-fill required fields from defaults or duplicated source rows.","Run the non-throwing pass first to collect missing fields for inline UI feedback.","Mark required columns clearly in forms and import templates."],"tags":["validation","required-fields","data-insert","not-null"],"backgroundTag":null,"analyzedSha":"d3caaf4e890acf64bd49b788cf6dc32b7644c895","analyzedAt":"2026-08-12T13:07:32.092Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}