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
- Send a plain object: customFields=<urlencoded JSON.stringify({ key: 'value' })>
- When no filtering is desired, omit the customFields parameter entirely instead of sending null/[]
- 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
- Send customFields only as a plain JSON object, URL-encoded
- Omit the parameter entirely when not filtering (never send 'null' or '[]')
- Remember both bad JSON and non-object JSON surface as the same 'valid JSON' error
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
- error-token-param-not-provided
- The "${property}.start" query parameter must be a valid date
- The "${property}.end" query parameter must be a valid date.
- The "customFields" query parameter must be a valid JSON.
- error-room-does-not-exist
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/d4cd7321b2e8a25d.
Report an issue: GitHub.