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
- Include every required field id in the customFields array — the error message names exactly which ids are missing
- Make the field optional in Administration > Omnichannel > Custom Fields if it should not block writes
- 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
- Derive the key list from required-field metadata at runtime
- Make fields optional when they should never block a visitor write
- Test integrations after admins add new required fields
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
- error-invalid-custom-field-value
- error-custom-field-not-allowed
- error-invalid-custom-field-value
- error-invalid-custom-field-value
- error-invalid-custom-field-value
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)