RocketChat/Rocket.Chat · error · Error

Invalid custom fields

Error message

Invalid custom fields

What it means

An internal guard inside GET /api/v1/livechat/rooms: after JSON.parse of the customFields query parameter, it fires when the parsed value is not a plain object (typeof !== 'object', an array, or null). Important nuance: this throw is immediately swallowed by the surrounding try/catch and re-thrown as 'The "customFields" query parameter must be a valid JSON.' — so clients never see the 'Invalid custom fields' text; every malformed shape (bad JSON or non-object JSON) surfaces as the JSON message.

Source

Thrown at apps/meteor/server/api/v1/omnichannel/rooms.ts:50

			const { sort, fields, query } = await this.parseJsonQuery();
			const { agents, departmentId, open, tags, roomName, onhold, queued, units } = this.queryParams;
			const { createdAt, customFields, closedAt } = this.queryParams;

			const createdAtParam = validateDateParams('createdAt', createdAt);
			const closedAtParam = validateDateParams('closedAt', closedAt);

			const hasAdminAccess = await hasPermissionAsync(this.user, 'view-livechat-rooms');
			const hasAgentAccess = (await hasPermissionAsync(this.user, 'view-l-room')) && agents?.includes(this.userId) && agents?.length === 1;
			if (!hasAdminAccess && !hasAgentAccess) {
				return API.v1.forbidden();
			}

			let parsedCf: { [key: string]: string } | undefined = undefined;
			if (customFields) {
				try {
					const parsedCustomFields = JSON.parse(customFields) as { [key: string]: string };
					if (typeof parsedCustomFields !== 'object' || Array.isArray(parsedCustomFields) || parsedCustomFields === null) {
						throw new Error('Invalid custom fields');
					}

					// Model's already checking for the keys, so we don't need to do it here.
					parsedCf = parsedCustomFields;
				} catch (e) {
					throw new Error('The "customFields" query parameter must be a valid JSON.');
				}
			}

			return API.v1.success(
				await findRooms({
					agents,
					roomName,
					departmentId,
					...(isBoolean(open) && { open: open === true || open === 'true' }),
					createdAt: createdAtParam,
					closedAt: closedAtParam,
					tags,

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Send a plain object: customFields=<urlencoded JSON.stringify({ key: 'value' })>
  2. When no filtering is desired, omit the customFields parameter entirely instead of sending null/[]
  3. Encode correctly: encodeURIComponent(JSON.stringify(fields))

Example fix

// before
const q = `customFields=${JSON.stringify([{ key: 'region', value: 'emea' }])}`; // array → rejected

// after
const q = `customFields=${encodeURIComponent(JSON.stringify({ region: 'emea' }))}`; // plain object
Defensive patterns

Strategy: validation

Validate before calling

function toCustomFieldsParam(fields) {
  if (!fields || typeof fields !== 'object' || Array.isArray(fields)) return ''; // omit instead of sending bad shapes
  return `customFields=${encodeURIComponent(JSON.stringify(fields))}`;
}

Type guard

function isPlainObject(v) {
  return typeof v === 'object' && v !== null && !Array.isArray(v);
}

Try / catch

try { await listRooms(query); } catch (e) { if (e.message?.includes('customFields')) { retryWithoutCustomFields(); return; } throw e; }

Prevention

When it happens

Trigger: Sending customFields=%5B%7B%7D%5D (a JSON array), customFields=null, customFields=%22abc%22 (a JSON string), or unparseable JSON — all end in the same 400 with the 'must be a valid JSON' message; passing an object whose keys are unknown to the LivechatCustomField model is NOT an error here (the model layer validates keys).

Common situations: Integrations sending an array of field objects; double-encoded JSON (a string containing JSON); forgetting encodeURIComponent so '&' inside the JSON truncates it; passing 'null' literally for 'no filter'.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


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