{"record":{"id":"29f0f1b6a11d4e67","repo":"angular/components","slug":"cannot-fetch-icon-from-url-safeurl","errorCode":null,"errorMessage":"Cannot fetch icon from URL \"${safeUrl}\".","messagePattern":"Cannot fetch icon from URL \"(.+?)\"\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/material/icon/icon-registry.ts","lineNumber":641,"sourceCode":"\n    return svg;\n  }\n\n  /**\n   * Returns an Observable which produces the string contents of the given icon. Results may be\n   * cached, so future calls with the same URL may not cause another HTTP request.\n   */\n  private _fetchIcon(iconConfig: SvgIconConfig): Observable<TrustedHTML> {\n    const {url: safeUrl, options} = iconConfig;\n    const withCredentials = options?.withCredentials ?? false;\n\n    if (!this._httpClient) {\n      throw getMatIconNoHttpProviderError();\n    }\n\n    // TODO: add an ngDevMode check\n    if (safeUrl == null) {\n      throw Error(`Cannot fetch icon from URL \"${safeUrl}\".`);\n    }\n\n    const url = this._sanitizer.sanitize(SecurityContext.RESOURCE_URL, safeUrl);\n\n    // TODO: add an ngDevMode check\n    if (!url) {\n      throw getMatIconFailedToSanitizeUrlError(safeUrl);\n    }\n\n    // Store in-progress fetches to avoid sending a duplicate request for a URL when there is\n    // already a request in progress for that URL. It's necessary to call share() on the\n    // Observable returned by http.get() so that multiple subscribers don't cause multiple XHRs.\n    const inProgressFetch = this._inProgressUrlFetches.get(url);\n\n    if (inProgressFetch) {\n      return inProgressFetch;\n    }\n","sourceCodeStart":623,"sourceCodeEnd":659,"githubUrl":"https://github.com/angular/components/blob/0411926e7d8ae06b32236ec1048a888cfad5abf2/src/material/icon/icon-registry.ts#L623-L659","documentation":"_fetchIcon builds the request from iconConfig.url; if that sanitized URL is null (e.g. the config was created without a URL), it throws a template error naming the attempted URL. This guards against config objects that only carry a literal (or nothing) being routed through the URL-fetch path.","triggerScenarios":"Internal path where a SvgIconConfig has url == null when the fetch logic runs — practically caused by calling an API that produced a null/bypassed URL value, e.g. passing undefined/null instead of a SafeResourceUrl into addSvgIcon.","commonSituations":"Passing a plain string or undefined instead of sanitizer.bypassSecurityTrustResourceUrl(...) and having it coerced to null; config created by addSvgIconLiteral but fetched via the URL path; refactor errors after version upgrades.","solutions":["Ensure a valid SafeResourceUrl is passed: sanitizer.bypassSecurityTrustResourceUrl('assets/icons.svg').","Check that the name/namespace passed to addSvgIcon matches what is used in [svgIcon] so the right config is fetched.","Log the registry config before fetching; replace null entries with real URLs or literal registrations."],"exampleFix":"// before\nregistry.addSvgIcon('gear', undefined as any);\n// after\nregistry.addSvgIcon('gear', this.sanitizer.bypassSecurityTrustResourceUrl('assets/gear.svg'));","handlingStrategy":"validation","validationCode":"const url = sanitizer.bypassSecurityTrustResourceUrl('assets/icons.svg');\nif (!url || !('changingThisBreaksApplicationSecurity' in url)) {\n  throw new Error('Icon URL must be a non-null SafeResourceUrl');\n}\nregistry.addSvgIcon('set', url);","typeGuard":"function isSafeResourceUrl(v: unknown): v is SafeResourceUrl {\n  return !!v && typeof v === 'object' &&\n    'changingThisBreaksApplicationSecurity' in (v as object);\n}","tryCatchPattern":"try {\n  await firstValueFrom(registry.getNamedSvgIcon(name));\n} catch (e) {\n  if ((e as Error).message.startsWith('Cannot fetch icon from URL')) {\n    console.error(`Icon config for \"${name}\" has no URL; register a literal instead`);\n  } else { throw e; }\n}","preventionTips":["Never pass undefined/plain string where a SafeResourceUrl is expected","Keep a single factory provider that builds all icon configs so URLs are set in one place","Log icon config map in dev mode to catch null URLs early"],"tags":["angular-material","icon-registry","url"],"backgroundTag":"invalid-icon-url","analyzedSha":"0411926e7d8ae06b32236ec1048a888cfad5abf2","analyzedAt":"2026-08-31T11:58:23.400Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}