{"record":{"id":"903a954f04510b0a","repo":"RocketChat/Rocket.Chat","slug":"the-customfields-query-parameter-must-be-a-valid","errorCode":null,"errorMessage":"The \"customFields\" query parameter must be a valid JSON.","messagePattern":"The \"customFields\" query parameter must be a valid JSON\\.","errorType":"validation","errorClass":"Error","httpStatus":400,"severity":"warning","filePath":"apps/meteor/server/api/v1/omnichannel/rooms.ts","lineNumber":56,"sourceCode":"\n\t\t\tconst hasAdminAccess = await hasPermissionAsync(this.user, 'view-livechat-rooms');\n\t\t\tconst hasAgentAccess = (await hasPermissionAsync(this.user, 'view-l-room')) && agents?.includes(this.userId) && agents?.length === 1;\n\t\t\tif (!hasAdminAccess && !hasAgentAccess) {\n\t\t\t\treturn API.v1.forbidden();\n\t\t\t}\n\n\t\t\tlet parsedCf: { [key: string]: string } | undefined = undefined;\n\t\t\tif (customFields) {\n\t\t\t\ttry {\n\t\t\t\t\tconst parsedCustomFields = JSON.parse(customFields) as { [key: string]: string };\n\t\t\t\t\tif (typeof parsedCustomFields !== 'object' || Array.isArray(parsedCustomFields) || parsedCustomFields === null) {\n\t\t\t\t\t\tthrow new Error('Invalid custom fields');\n\t\t\t\t\t}\n\n\t\t\t\t\t// Model's already checking for the keys, so we don't need to do it here.\n\t\t\t\t\tparsedCf = parsedCustomFields;\n\t\t\t\t} catch (e) {\n\t\t\t\t\tthrow new Error('The \"customFields\" query parameter must be a valid JSON.');\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn API.v1.success(\n\t\t\t\tawait findRooms({\n\t\t\t\t\tagents,\n\t\t\t\t\troomName,\n\t\t\t\t\tdepartmentId,\n\t\t\t\t\t...(isBoolean(open) && { open: open === true || open === 'true' }),\n\t\t\t\t\tcreatedAt: createdAtParam,\n\t\t\t\t\tclosedAt: closedAtParam,\n\t\t\t\t\ttags,\n\t\t\t\t\tcustomFields: parsedCf,\n\t\t\t\t\tonhold,\n\t\t\t\t\tqueued,\n\t\t\t\t\tunits,\n\t\t\t\t\tquery,\n\t\t\t\t\toptions: { offset, count, sort, fields },","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/server/api/v1/omnichannel/rooms.ts#L38-L74","documentation":"Thrown by GET livechat/rooms when the customFields query param either fails JSON.parse or parses to a non-object (array, primitive, null). The try/catch wraps both JSON.parse and the shape check, so any malformed JSON or wrong-typed value surfaces as this generic message ('Invalid custom fields' is caught and re-thrown as this).","triggerScenarios":"GET livechat/rooms?customFields=<not json> (e.g. 'foo', '{key:val}' unquoted, '[]' array, '\"str\"'). Any value that JSON.parse rejects OR that parses to a non-plain-object triggers it.","commonSituations":"Client concatenates key=value pairs instead of building a JSON object; user typed raw text; frontend sent an array of pairs instead of a map; missing URL encoding of braces/quotes breaks the parse.","solutions":["Send customFields as a URL-encoded JSON object: customFields=%7B%22department%22%3A%22sales%22%7D.","Build the object programmatically (JSON.stringify) rather than template-concatenating.","Validate typeof parsed === 'object' && !Array.isArray && !== null on the client before sending.","Omit the param when no custom-field filter is needed."],"exampleFix":"// before\nGET('/api/v1/livechat/rooms?customFields=' + rawInput);\n\n// after\nconst cf = JSON.parse(rawInput);\nif (typeof cf !== 'object' || Array.isArray(cf) || cf === null) throw new ClientError('bad cf');\nGET('/api/v1/livechat/rooms?customFields=' + encodeURIComponent(JSON.stringify(cf)));","handlingStrategy":"type-guard","validationCode":"function buildCustomFieldsParam(input: unknown) {\n  if (input == null) return undefined;\n  if (typeof input !== 'object' || Array.isArray(input)) throw new ClientError('customFields must be object');\n  return encodeURIComponent(JSON.stringify(input));\n}","typeGuard":"const isCustomFieldsMap = (v: unknown): v is Record<string, string> =>\n  typeof v === 'object' && v !== null && !Array.isArray(v) && Object.values(v).every((x) => typeof x === 'string');","tryCatchPattern":"try {\n  await GET('/api/v1/livechat/rooms', { customFields: buildCustomFieldsParam(cf) });\n} catch (e) {\n  if (/must be a valid JSON/i.test(e.message)) { showCfError(); return; }\n  throw e;\n}","preventionTips":["Build the param via JSON.stringify of a validated object — never template-concatenate.","URL-encode the serialized JSON.","Omit the param when no custom-field filter is needed."],"tags":["omnichannel","livechat","query-params","json-validation","rooms-list"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}