RocketChat/Rocket.Chat · error · Error

Missing required custom fields

Error message

Missing required custom fields: ${errors.join(', ')}

What it means

validateRequiredCustomFields (used by setMultipleVisitorCustomFields before writing visitor/room custom fields) compares the list of field keys you are about to set against every field marked required in the definition. If any required field id is absent from your keys array, it throws a plain Error listing the missing ids in the message — note it has no error code, only the interpolated text.

Solutions

  1. Include every required field id in the customFields array — the error message names exactly which ids are missing
  2. Make the field optional in Administration > Omnichannel > Custom Fields if it should not block writes
  3. Fetch required ids at runtime (GET /api/v1/livechat/custom-fields, filter required) instead of hardcoding the list

Example fix

// before
await setMultipleVisitorCustomFields({ token, customFields: [{ key: 'company', value: 'ACME', overwrite: true }] }); // 'address' required

// after
await setMultipleVisitorCustomFields({ token, customFields: [
  { key: 'company', value: 'ACME', overwrite: true },
  { key: 'address', value: '1 Main St', overwrite: true },
] });
Defensive patterns

Strategy: validation

Validate before calling

const allFields = await LivechatCustomField.find().toArray();
const requiredIds = allFields.filter((f) => f.required).map((f) => f._id);
const missing = requiredIds.filter((id) => !keys.includes(id));
if (missing.length) throw new Error(`Missing required custom fields: ${missing.join(', ')}`);
await setMultipleVisitorCustomFields(params);

Type guard

const coversRequired = (keys: string[], required: string[]): boolean =>
  required.every((id) => keys.includes(id));

Try / catch

try {
  await setMultipleVisitorCustomFields(params);
} catch (err) {
  if (err instanceof Error && err.message.startsWith('Missing required custom fields')) {
    // parse field ids from the message, add them with valid values, retry
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling setMultipleVisitorCustomFields (visitor registration/custom-field batch flows) with a keys list that covers only some fields, while at least one field in LivechatCustomField has required=true.

Common situations: New required field added by admins after the integration was written; webhook sends a dynamic subset of fields; required field hidden in the chat widget form.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@2a7de45707 (2026-08-18). Data as JSON: /api/errors/42893f2735c5d56e. Report an issue: GitHub.

Appendix: source

Thrown at apps/meteor/server/lib/omnichannel/custom-fields.ts:21

import { livechatLogger } from './logger';
import { i18n } from '../../../app/utils/lib/i18n';

export const validateRequiredCustomFields = (
	customFields: string[],
	livechatCustomFields: Pick<ILivechatCustomField, '_id' | 'required'>[],
) => {
	const errors: string[] = [];
	const requiredCustomFields = livechatCustomFields.filter((field) => field.required);

	requiredCustomFields.forEach((field) => {
		if (!customFields.find((f) => f === field._id)) {
			errors.push(field._id);
		}
	});

	if (errors.length > 0) {
		throw new Error(`Missing required custom fields: ${errors.join(', ')}`);
	}
};

export async function updateContactsCustomFields(
	contact: ILivechatContact,
	validCustomFields: {
		key: string;
		value: string;
		overwrite: boolean;
	}[],
): Promise<void> {
	const contactCustomFieldsToUpdate = validCustomFields.reduce(
		(prev, curr) => {
			if (curr.overwrite || !contact?.customFields?.[curr.key]) {
				prev[`customFields.${curr.key}`] = curr.value;
				return prev;
			}
			prev.conflictingFields ??= contact.conflictingFields || [];

View on GitHub (pinned to 2a7de45707)