RocketChat/Rocket.Chat · error · Meteor.Error

error-invalid-query

error-invalid-query

Error message

Invalid query parameter provided: "${params.query}"

What it means

parseJsonQuery parses the deprecated query param only when ALLOW_UNSAFE_QUERY_AND_FIELDS_API_PARAMS=TRUE, using ejson.parse followed by clean() against the route allowlist config. If parsing or cleaning throws, the failure is logged and rethrown as Meteor error-invalid-query with the raw param echoed in the message. The query param is deprecated for security reasons (it allowed arbitrary Mongo queries) and logs a deprecation warning targeting removal in 9.0.0.

Source

Thrown at apps/meteor/server/api/lib/parseJsonQuery.ts:124

			fields = Object.assign(fields, API.v1.limitedUserFieldsToExcludeIfIsPrivilegedUser);
		} else {
			fields = Object.assign(fields, API.v1.limitedUserFieldsToExclude);
		}
	}

	let query: Record<string, any> = {};
	if (typeof params?.query === 'string' && isUnsafeQueryParamsAllowed) {
		apiDeprecationLogger.parameter(route, 'query', '9.0.0', response, messageGenerator);
		try {
			query = ejson.parse(params.query);
			query = clean(query, pathAllowConf.def);
		} catch (e) {
			logger.warn({
				msg: 'Invalid query parameter provided',
				query: params.query,
				err: e,
			});
			throw new Meteor.Error('error-invalid-query', `Invalid query parameter provided: \"${params.query}\"`, {
				helperMethod: 'parseJsonQuery',
			});
		}
	}

	// Verify the user has permission to query the fields they are
	if (typeof query === 'object') {
		let nonQueryableFields = Object.keys(API.v1.defaultFieldsToExclude);

		if (isUsersRoute) {
			if (canViewFullOtherUserInfo) {
				nonQueryableFields = nonQueryableFields.concat(Object.keys(API.v1.limitedUserFieldsToExcludeIfIsPrivilegedUser));
			} else {
				nonQueryableFields = nonQueryableFields.concat(Object.keys(API.v1.limitedUserFieldsToExclude));
			}
		}

		const containsQueryFields = queryFields.length > 0;

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Send valid strict JSON and URL-encode it: query=%7B%22name%22%3A%7B%22%24regex%22%3A%22a%22%7D%7D
  2. Prefer endpoint-specific filter params (e.g. users.list's term/email) over the deprecated query param
  3. Plan migration away from the param before 9.0.0 removes it

Example fix

// before
GET /api/v1/channels.list?query={ 'name': { $regex: 'a' } } // single quotes, unencoded

// after
GET /api/v1/channels.list?query=%7B%22name%22%3A%7B%22%24regex%22%3A%22a%22%7D%7D
Defensive patterns

Strategy: validation

Validate before calling

function buildQueryParam(query: Record<string, unknown>): string {
  const json = JSON.stringify(query); // throws client-side on bad structure
  JSON.parse(json); // round-trip assertion: strict-JSON safe
  return encodeURIComponent(json);
}

Type guard

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

Try / catch

try {
  await client.get('/api/v1/channels.list', { params: { query } });
} catch (e: any) {
  if (e?.response?.data?.errorType === 'error-invalid-query') {
    throw new ValidationError(`query param is not valid JSON: ${e.response.data.message}`);
  }
  throw e;
}

Prevention

When it happens

Trigger: With the env var TRUE, sending query=not json, query={name:} (trailing colon), unescaped quotes, or values clean() rejects (e.g. keys containing dots into disallowed paths) on any list endpoint.

Common situations: Re-enabling legacy client behavior via the escape-hatch env var and hitting EJSON's stricter parsing (no single quotes, no trailing commas); hand-concatenated query strings missing encodeURIComponent; upgrading between versions where the param became gated and old payloads only fail once the env var is switched on.

Related errors


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