RocketChat/Rocket.Chat · error · Error
error-custom-field-not-allowed
error-custom-field-not-allowed
Error message
error-custom-field-not-allowed
What it means
After validating known fields, validateCustomFields walks every key of the submitted customFields object and rejects any key not present in allowedCustomFields when ignoreAdditionalFields is false. This is a closed-world check: the payload may only contain fields that are defined (and passed in as allowed) — unknown properties are an error, not ignored.
Source
Thrown at apps/meteor/server/lib/omnichannel/contacts/validateCustomFields.ts:50
if (cf.regexp) {
const regex = new RegExp(cf.regexp);
if (!regex.test(cfValue)) {
if (ignoreValidationErrors) {
continue;
}
throw new Error(i18n.t('error-invalid-custom-field-value', { field: cf.label || cf._id }));
}
}
validValues[cf._id] = cfValue;
}
if (!ignoreAdditionalFields) {
const allowedCustomFieldIds = new Set(allowedCustomFields.map((cf) => cf._id));
for (const key in customFields) {
if (!allowedCustomFieldIds.has(key)) {
throw new Error(i18n.t('error-custom-field-not-allowed', { key }));
}
}
}
return validValues;
}
View on GitHub (pinned to b2c16d5842)
Solutions
- Remove keys that are not defined custom-field ids, or create the missing field in Administration > Omnichannel > Custom Fields
- Whitelist client-side: filter the payload to ids returned by GET /api/v1/livechat/custom-fields before submitting
- For tolerant ingestion paths, use a code path that passes ignoreAdditionalFields: true
Example fix
// before
customFields: { company: 'ACME', internal_note: 'x' } // 'internal_note' is not a defined field
// after
const defined = new Set((await LivechatCustomField.find().toArray()).map((f) => f._id));
customFields = Object.fromEntries(Object.entries(customFields).filter(([k]) => defined.has(k))); Defensive patterns
Strategy: validation
Validate before calling
const allowed = new Set((await LivechatCustomField.find().toArray()).map((f) => f._id)); const filtered = Object.fromEntries(Object.entries(customFields).filter(([k]) => allowed.has(k))); // pass `filtered` instead of the raw payload
Type guard
const containsOnlyAllowedKeys = (payload: Record<string, unknown>, allowed: Set<string>): boolean => Object.keys(payload).every((k) => allowed.has(k));
Try / catch
try {
await registerContact(params, userId);
} catch (err) {
if (err instanceof Error && err.message.includes('error-custom-field-not-allowed')) {
// message names the offending key: remove it or define the field, then retry
}
throw err;
} Prevention
- Never reuse the customFields object to carry client metadata
- Filter payloads against the live field list before submit
- When deleting a custom field, clean up clients/configs that still emit it
When it happens
Trigger: Submitting customFields containing a key that is not a defined Livechat Custom Field id (typo, stale field, client-side bookkeeping property) through a code path that does not set ignoreAdditionalItems/ignoreAdditionalFields.
Common situations: A custom field was deleted server-side but old clients still send it; client injects metadata keys like '_updatedAt' or 'source' into the same object; copy-paste field id with different casing.
Related errors
- error-invalid-custom-field-value
- Missing required custom fields: ${errors.join(', ')}
- invalid-custom-field
- error-invalid-custom-field-value
- error-invalid-custom-field-value
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/4d6c940e77afa949.
Report an issue: GitHub.