{"record":{"id":"068003c6903d4e15","repo":"RocketChat/Rocket.Chat","slug":"error-avatar-invalid-url","errorCode":"error-avatar-invalid-url","errorMessage":"Invalid avatar URL: ${dataURI}","messagePattern":"Invalid avatar URL: (.+?)","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/lib/users/setUserAvatar.ts","lineNumber":117,"sourceCode":"\t\treturn;\n\t}\n\n\tconst { buffer, type } = await (async (): Promise<{ buffer: Buffer; type: string }> => {\n\t\tif (service === 'url' && typeof dataURI === 'string') {\n\t\t\tlet response: Response;\n\n\t\t\ttry {\n\t\t\t\tresponse = await fetch(dataURI, {\n\t\t\t\t\tignoreSsrfValidation: false,\n\t\t\t\t\tallowList: settings.get<string>('SSRF_Allowlist'),\n\t\t\t\t});\n\t\t\t} catch (e) {\n\t\t\t\tSystemLogger.info({\n\t\t\t\t\tmsg: 'Not a valid response from the avatar url',\n\t\t\t\t\turl: dataURI,\n\t\t\t\t\terr: e,\n\t\t\t\t});\n\t\t\t\tthrow new Meteor.Error('error-avatar-invalid-url', `Invalid avatar URL: ${dataURI}`, {\n\t\t\t\t\tfunction: 'setUserAvatar',\n\t\t\t\t\turl: dataURI,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (response.status !== 200) {\n\t\t\t\tif (response.status !== 404) {\n\t\t\t\t\tSystemLogger.info({\n\t\t\t\t\t\tmsg: 'Error while handling the setting of the avatar from a url',\n\t\t\t\t\t\turl: dataURI,\n\t\t\t\t\t\tusername: user.username,\n\t\t\t\t\t\tstatus: response.status,\n\t\t\t\t\t});\n\t\t\t\t\tthrow new Meteor.Error(\n\t\t\t\t\t\t'error-avatar-url-handling',\n\t\t\t\t\t\t`Error while handling avatar setting from a URL (${dataURI}) for ${user.username}`,\n\t\t\t\t\t\t{ function: 'RocketChat.setUserAvatar', url: dataURI, username: user.username },\n\t\t\t\t\t);","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/2a7de457074cbb4d4373fbd9a4e5bea292c9c764/apps/meteor/server/lib/users/setUserAvatar.ts#L99-L135","documentation":"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').","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use a publicly reachable https URL that serves the image directly.","For legitimate internal hosts, add them to the SSRF_Allowlist setting.","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).","Verify DNS resolution and egress from the Rocket.Chat server host itself (curl the URL from that machine)."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Cheap client-side pre-checks; the server fetch is the authority\nimport { isURL } from 'validator';\n\nconst isValidAvatarUrl = (url: string): boolean =>\n  isURL(url, { protocols: ['http', 'https'], require_protocol: true }) &&\n  !/^(https?:\\/\\/)?(localhost|127\\.|10\\.|192\\.168\\.|172\\.(1[6-9]|2\\d|3[01])\\.)/.test(url); // SSRF-blocked ranges","typeGuard":"const isPublicHttpUrl = (url: string): boolean => {\n  try {\n    const u = new URL(url);\n    return (u.protocol === 'http:' || u.protocol === 'https:') && !isPrivateHostname(u.hostname);\n  } catch {\n    return false;\n  }\n};","tryCatchPattern":"try {\n  await setUserAvatar(user, url, undefined, 'url');\n} catch (e: any) {\n  if (e.error === 'error-avatar-invalid-url') {\n    logger.warn({ msg: 'Avatar URL unreachable or SSRF-blocked', url: e.details?.url });\n    return setUserAvatar(user, '', undefined, 'initials'); // fall back to initials avatar\n  }\n  throw e;\n}","preventionTips":["Only submit avatar URLs the server can reach: public https links, or internal hosts explicitly added to SSRF_Allowlist.","Do not assume a URL that loads in the browser is loadable from the server.","For internal images, upload the bytes (data-URI/rest) instead of the URL.","Check SystemLogger for the underlying fetch error before assuming the URL string is wrong."],"tags":["avatar","ssrf","network","url","security"],"backgroundTag":"url-fetch-failed","analyzedSha":"2a7de457074cbb4d4373fbd9a4e5bea292c9c764","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}