{"record":{"id":"c8d5d6fd78064e97","repo":"angular/components","slug":"could-not-sanitize-html-html","errorCode":null,"errorMessage":"Could not sanitize HTML: ${html}","messagePattern":"Could not sanitize HTML: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/cdk/private/inner-html.ts","lineNumber":22,"sourceCode":" *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {SecurityContext} from '@angular/core';\nimport {DomSanitizer, SafeHtml} from '@angular/platform-browser';\nimport {trustedHTMLFromString} from './trusted-types';\n\n// !!!Note!!! this file isn't synced into g3, but is replaced with a version that uses\n// internal-specific APIs. The internal version may have to be updated if the signature of\n// the function changes.\n\n/** Sanitizes and sets the `innerHTML` of an element. */\nexport function _setInnerHtml(element: HTMLElement, html: SafeHtml, sanitizer: DomSanitizer): void {\n  const cleanHtml = sanitizer.sanitize(SecurityContext.HTML, html);\n\n  if (cleanHtml === null && (typeof ngDevMode === 'undefined' || ngDevMode)) {\n    throw new Error(`Could not sanitize HTML: ${html}`);\n  }\n\n  element.innerHTML = trustedHTMLFromString(cleanHtml || '') as unknown as string;\n}\n","sourceCodeStart":4,"sourceCodeEnd":27,"githubUrl":"https://github.com/angular/components/blob/0411926e7d8ae06b32236ec1048a888cfad5abf2/src/cdk/private/inner-html.ts#L4-L27","documentation":"_setInnerHtml sanitizes a SafeHtml value via DomSanitizer before assigning it to element.innerHTML (used by the LiveAnnouncer's announce). If sanitizer.sanitize returns null, the value could not be made safe and the assignment is aborted with this dev-mode error to avoid injecting unsafe markup.","triggerScenarios":"Calling announce(text) where the text resolves to unsafe/bypassed HTML that the sanitizer refuses (e.g. a value created via bypassSecurityTrustHtml in an inconsistent state, or a non-SafeHtml value that sanitizes to null, such as certain malformed/oversized inputs).","commonSituations":"Passing raw (non-trusted) strings into APIs expecting SafeHtml; custom announcer code reusing _setInnerHtml with user input that fails sanitization; version changes in sanitizer behavior making previously-accepted HTML return null.","solutions":["Pass plain text to announce() — it doesn't need HTML sanitization for normal announcements.","If HTML is intentional, wrap it with sanitizer.bypassSecurityTrustHtml only for fully trusted, reviewed content.","Inspect the failing html value in the error message and fix whatever produces an unsanitizable value.","Upgrade/verify Angular sanitizer behavior if the same content previously worked."],"exampleFix":"// before\nannouncer.announce(someUserHtml, 'assertive');\n// after\nannouncer.announce(plainTextMessage, 'assertive');","handlingStrategy":"try-catch","validationCode":"if (typeof html !== 'string' && !isSafeHtmlLike(html)) {\n  throw new Error('announce expects a plain string or a trusted SafeHtml value');\n}","typeGuard":null,"tryCatchPattern":"try {\n  announcer.announce(message);\n} catch (e) {\n  if ((e as Error).message.startsWith('Could not sanitize HTML')) {\n    announcer.announce(stripHtml(message));\n  } else throw e;\n}","preventionTips":["Announce plain text, not HTML.","Never build SafeHtml from untrusted input; reserve bypassSecurityTrustHtml for audited static markup.","Keep the announced strings simple and free of markup after transformations."],"tags":["angular","cdk","security","sanitization","live-announcer"],"backgroundTag":"html-sanitization-failed","analyzedSha":"0411926e7d8ae06b32236ec1048a888cfad5abf2","analyzedAt":"2026-08-31T11:58:23.400Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}