RocketChat/Rocket.Chat · error · Meteor.Error

error-avatar-invalid-url

error-avatar-invalid-url

Error message

Invalid avatar URL: ${dataURI}

What it means

With service 'url', the server fetches the avatar URL with SSRF validation enabled (private/loopback addresses blocked unless present in the SSRF_Allowlist setting). If the fetch itself throws — DNS failure, connection refused, TLS error, or an SSRF-blocked address — error-avatar-invalid-url is thrown; the underlying err is logged via SystemLogger ('Not a valid response from the avatar url').

Source

Thrown at apps/meteor/server/lib/users/setUserAvatar.ts:117

		return;
	}

	const { buffer, type } = await (async (): Promise<{ buffer: Buffer; type: string }> => {
		if (service === 'url' && typeof dataURI === 'string') {
			let response: Response;

			try {
				response = await fetch(dataURI, {
					ignoreSsrfValidation: false,
					allowList: settings.get<string>('SSRF_Allowlist'),
				});
			} catch (e) {
				SystemLogger.info({
					msg: 'Not a valid response from the avatar url',
					url: dataURI,
					err: e,
				});
				throw new Meteor.Error('error-avatar-invalid-url', `Invalid avatar URL: ${dataURI}`, {
					function: 'setUserAvatar',
					url: dataURI,
				});
			}

			if (response.status !== 200) {
				if (response.status !== 404) {
					SystemLogger.info({
						msg: 'Error while handling the setting of the avatar from a url',
						url: dataURI,
						username: user.username,
						status: response.status,
					});
					throw new Meteor.Error(
						'error-avatar-url-handling',
						`Error while handling avatar setting from a URL (${dataURI}) for ${user.username}`,
						{ function: 'RocketChat.setUserAvatar', url: dataURI, username: user.username },
					);

View on GitHub (pinned to 2a7de45707)

Solutions

  1. Use a publicly reachable https URL that serves the image directly.
  2. For legitimate internal hosts, add them to the SSRF_Allowlist setting.
  3. Check server logs for the 'Not a valid response from the avatar url' entry to see the true fetch error (DNS vs SSRF vs TLS).
  4. Verify DNS resolution and egress from the Rocket.Chat server host itself (curl the URL from that machine).
Defensive patterns

Strategy: try-catch

Validate before calling

// Cheap client-side pre-checks; the server fetch is the authority
import { isURL } from 'validator';

const isValidAvatarUrl = (url: string): boolean =>
  isURL(url, { protocols: ['http', 'https'], require_protocol: true }) &&
  !/^(https?:\/\/)?(localhost|127\.|10\.|192\.168\.|172\.(1[6-9]|2\d|3[01])\.)/.test(url); // SSRF-blocked ranges

Type guard

const isPublicHttpUrl = (url: string): boolean => {
  try {
    const u = new URL(url);
    return (u.protocol === 'http:' || u.protocol === 'https:') && !isPrivateHostname(u.hostname);
  } catch {
    return false;
  }
};

Try / catch

try {
  await setUserAvatar(user, url, undefined, 'url');
} catch (e: any) {
  if (e.error === 'error-avatar-invalid-url') {
    logger.warn({ msg: 'Avatar URL unreachable or SSRF-blocked', url: e.details?.url });
    return setUserAvatar(user, '', undefined, 'initials'); // fall back to initials avatar
  }
  throw e;
}

Prevention

When it happens

Trigger: Avatar URL unreachable from the server (reachable from the browser is not enough); http://localhost/... or 10.x/192.168.x addresses blocked by SSRF protection; typo'd domain (DNS failure); expired TLS certificate on the image host; firewall blocking server egress.

Common situations: Client passes an intranet/internal-CDN URL the public server cannot reach; developers testing with localhost image links; internal host not added to SSRF_Allowlist; image domain expired or DNS records removed.

Related errors


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