RocketChat/Rocket.Chat · error · Meteor.Error

invalid-roomCustomFields-type

invalid-roomCustomFields-type

Error message

Invalid roomCustomFields type

What it means

Thrown by saveRoomCustomFields when Match.test(roomCustomFields, Object) fails (saveRoomCustomFields.ts:16). In Meteor's check semantics, Object matches plain objects only — null, undefined, primitives, and arrays all fail. Code 'invalid-roomCustomFields-type', details { function: 'RocketChat.saveRoomCustomFields' }.

Source

Thrown at apps/meteor/server/lib/rooms/settings/saveRoomCustomFields.ts:16

import { Rooms, Subscriptions } from '@rocket.chat/models';
import { Match } from 'meteor/check';
import { Meteor } from 'meteor/meteor';
import type { UpdateResult } from 'mongodb';

import { notifyOnSubscriptionChangedByRoomId } from '../../notifyListener';

export const saveRoomCustomFields = async function (rid: string, roomCustomFields: Record<string, any>): Promise<UpdateResult> {
	if (!Match.test(rid, String)) {
		throw new Meteor.Error('invalid-room', 'Invalid room', {
			function: 'RocketChat.saveRoomCustomFields',
		});
	}

	if (!Match.test(roomCustomFields, Object)) {
		throw new Meteor.Error('invalid-roomCustomFields-type', 'Invalid roomCustomFields type', {
			function: 'RocketChat.saveRoomCustomFields',
		});
	}

	const ret = await Rooms.setCustomFieldsById(rid, roomCustomFields);

	// Update customFields of any user's Subscription related with this rid
	const { modifiedCount } = await Subscriptions.updateCustomFieldsByRoomId(rid, roomCustomFields);
	if (modifiedCount) {
		void notifyOnSubscriptionChangedByRoomId(rid);
	}

	return ret;
};

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Pass a plain object, defaulting to {} when there is nothing to set
  2. Parse before calling: typeof fields === 'string' ? JSON.parse(fields) : fields
  3. Reject arrays at the boundary — they are not valid custom-fields maps
  4. Match on code 'invalid-roomCustomFields-type' to report a payload problem rather than a room problem

Example fix

// before
await saveRoomCustomFields(rid, body.customFields); // arrives as '{"dept":"sales"}' string

// after
const customFields = typeof body.customFields === 'string' ? JSON.parse(body.customFields) : body.customFields ?? {};
await saveRoomCustomFields(rid, customFields);
Defensive patterns

Strategy: type-guard

Validate before calling

const isPlainObject = (v: unknown): v is Record<string, unknown> =>
	typeof v === 'object' && v !== null && !Array.isArray(v);
if (!isPlainObject(customFields)) {
	throw new Meteor.Error('invalid-roomCustomFields-type', 'Invalid roomCustomFields type');
}
await saveRoomCustomFields(rid, customFields);

Type guard

const isPlainObject = (v: unknown): v is Record<string, unknown> =>
	typeof v === 'object' && v !== null && !Array.isArray(v);

Prevention

When it happens

Trigger: Passing null/undefined defaults (fields ?? null); passing an array of key/value pairs instead of a map; passing a JSON string that was never parsed (typeof 'string'); body-parsers returning a primitive for empty payloads.

Common situations: REST integrations sending application/x-www-form-urlencoded where customFields arrives as a string; code doing JSON.stringify at the caller but forgetting JSON.parse at the callee; treating an empty payload as null instead of {}.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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