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
- Add the needed type to API_Shield_Types (comma-separated) in Administration -> General -> REST API
- Check exact spelling and case of the type parameter against the configured list
- 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
- Match badge type lists between your embed code and the workspace's API_Shield_Types setting
- Treat a whitelisted-type failure as permanent until the admin list changes - do not re-request on every page view
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
- error-endpoint-disabled
- error-id-param-not-provided
- error-name-param-not-provided
- message-length-exceeds-character-limit
- error-blocked-username
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)