RocketChat/Rocket.Chat · error · Meteor.Error

error-shield-disabled

error-shield-disabled

Error message

This shield type is disabled

What it means

shield.svg validates the optional type query parameter against the comma-separated API_Shield_Types setting (misc.ts:228-240). Unless that setting is '*' (the default), a type not present in the list throws error-shield-disabled. This only fires after an admin narrowed the whitelist - with the default '*' every type passes.

Solutions

  1. Add the needed type to API_Shield_Types (comma-separated) in Administration -> General -> REST API
  2. Check exact spelling and case of the type parameter against the configured list
  3. Only set '*' if exposing every badge type is acceptable for your security posture

Example fix

# before
 GET /api/v1/shield.svg?type=avatar&name=alice  # API_Shield_Types = 'online,userCount'
 # => error-shield-disabled

 # after: admin adds the type (or uses '*')
 POST /api/v1/settings/API_Shield_Types  {"value": "online,userCount,avatar"}
 GET /api/v1/shield.svg?type=avatar&name=alice
Defensive patterns

Strategy: validation

Validate before calling

const allowedTypes = await fetchTypesFromConfig(); // e.g. read API_Shield_Types once via an admin settings call, or cache the known-good list
const type = 'online';
if (allowedTypes !== '*' && !allowedTypes.split(',').map((t) => t.trim()).includes(type)) {
  throw new Error(`Shield type '${type}' not allowed; configured: ${allowedTypes}`);
}
await fetch(`${server}/api/v1/shield.svg?type=${type}`);

Type guard

const isAllowedShieldType = (type: string, configured: string): boolean =>
  configured === '*' || configured.split(',').map((t) => t.trim()).includes(type);

Try / catch

try {
  await fetch(`${server}/api/v1/shield.svg?type=${type}`);
} catch (err) {
  if (err?.error === 'error-shield-disabled') {
    dropBadge(type); // type not whitelisted on this workspace - stop requesting it
  }
}

Prevention

When it happens

Trigger: GET /api/v1/shield.svg?type=<t> where API_Shield_Types is e.g. 'online,userCount' and <t> is any other value (avatar, channel, etc.), including case mismatches, since the comparison is exact after trimming.

Common situations: Admin restricts shields to a few types after a data-exposure review and existing badges of other types start failing; typos or wrong casing in the type parameter; documentation examples using types the workspace never whitelisted.

Related errors


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

Appendix: source

Thrown at apps/meteor/server/api/v1/misc.ts:237

	async function action() {
		const { type, icon } = this.queryParams;
		let { channel, name } = this.queryParams;
		if (!settings.get('API_Enable_Shields')) {
			throw new Meteor.Error('error-endpoint-disabled', 'This endpoint is disabled', {
				route: '/api/v1/shield.svg',
			});
		}

		const types = settings.get<string>('API_Shield_Types');
		if (
			type &&
			types !== '*' &&
			!types
				.split(',')
				.map((t: string) => t.trim())
				.includes(type)
		) {
			throw new Meteor.Error('error-shield-disabled', 'This shield type is disabled', {
				route: '/api/v1/shield.svg',
			});
		}
		const hideIcon = icon === 'false';
		if (hideIcon && !name?.trim()) {
			return API.v1.failure('Name cannot be empty when icon is hidden');
		}

		let text;
		let backgroundColor = '#4c1';
		switch (type) {
			case 'online':
				if (Date.now() - onlineCacheDate > cacheInvalid) {
					onlineCache = await Users.countUsersNotOffline();
					onlineCacheDate = Date.now();
				}

				text = `${onlineCache} ${i18n.t('Online')}`;

View on GitHub (pinned to 2a7de45707)