basecamp/trix · error · TypeError
TRUSTED_TYPES_POLICY configuration option must provide a "cr
Error message
TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.
What it means
DOMPurify validates a caller-supplied TRUSTED_TYPES_POLICY at _parseConfig time: the object must expose both a createHTML and a createScriptURL function. If TRUSTED_TYPES_POLICY is provided but createHTML is missing or not a function, DOMPurify throws this TypeError rather than silently producing unsigned/unsafe output. This fail-closed check also prevents a stale foreign policy from signing later 'default' results (see GHSA-vxr8-fq34-vvx9).
Source
Thrown at action_text-trix/app/assets/javascripts/trix.js:2651
/* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */
if (WHOLE_DOCUMENT) {
addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);
}
/* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */
if (ALLOWED_TAGS.table) {
addToSet(ALLOWED_TAGS, ['tbody']);
delete FORBID_TAGS.tbody;
}
// Re-derive the active Trusted Types policy from this configuration on
// every parse. The active policy must never be sticky closure state that
// outlives the config that set it: a caller-supplied policy left in place
// after `clearConfig()` — or after a later call that supplied none, or
// `TRUSTED_TYPES_POLICY: null` — could sign a subsequent "default"
// `RETURN_TRUSTED_TYPE` result with a foreign, possibly unsafe policy.
// See GHSA-vxr8-fq34-vvx9.
if (cfg.TRUSTED_TYPES_POLICY) {
if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') {
throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');
}
if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {
throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');
}
// A caller-supplied policy applies to this configuration only.
const previousTrustedTypesPolicy = trustedTypesPolicy;
trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;
// Sign local variables required by `sanitize`. If the supplied policy's
// `createHTML` is circular (i.e. it calls `DOMPurify.sanitize`), this
// throws via the re-entrancy guard. Restore the previous policy first so
// the instance is not left in a poisoned state. See #1422.
try {
emptyHTML = _createTrustedHTML('');
} catch (error) {
trustedTypesPolicy = previousTrustedTypesPolicy;
throw error;
}
} else if (cfg.TRUSTED_TYPES_POLICY === null) {View on GitHub (pinned to 4700401311)
Solutions
- Add a createHTML function to the object passed as TRUSTED_TYPES_POLICY.
- Check spelling/casing: the key must be exactly createHTML (and createScriptURL), not createHtml.
- If you only need one direction, still provide both methods (unused ones can be identity functions).
- Use trustedTypes.createPolicy(...) to build the object, then verify both methods exist before passing it.
Example fix
// before
DOMPurify.sanitize(dirty, { TRUSTED_TYPES_POLICY: { createScriptURL: (s) => s } });
// after
DOMPurify.sanitize(dirty, {
TRUSTED_TYPES_POLICY: {
createHTML: (s) => s,
createScriptURL: (s) => s
}
}); Defensive patterns
Strategy: type-guard
Validate before calling
if (cfg.TRUSTED_TYPES_POLICY && typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') {
throw new Error('Refusing to configure: TRUSTED_TYPES_POLICY.createHTML is missing');
} Type guard
const hasCreateHTML = (p) => !!p && typeof p.createHTML === 'function';
Try / catch
try {
DOMPurify.sanitize(dirty, { TRUSTED_TYPES_POLICY: policy });
} catch (e) {
if (String(e.message).includes('createHTML')) {
console.error('Supplied policy lacks createHTML; fix policy object.');
} else { throw e; }
} Prevention
- Always build policies with trustedTypes.createPolicy(name, { createHTML, createScriptURL }).
- Match exact casing: createHTML and createScriptURL.
- Validate the policy object in a wrapper around all DOMPurify.sanitize calls.
- Re-verify the policy after clearConfig() or config swaps.
When it happens
Trigger: Calling DOMPurify.addHook-free configuration such as DOMPurify.sanitize(dirty, { TRUSTED_TYPES_POLICY: someObject }) where someObject has no createHTML function (e.g. only createScriptURL, or a TrustedTypes policy object that is null/partially constructed), or after clearConfig() followed by a config supplying only one hook.
Common situations: Hand-rolling a policy object and forgetting one of the two required methods; passing a native TrustedTypes policy created with only createHTML; typos in property names (createHtml vs createHTML); passing the wrong variable (a config object instead of a policy).
Related errors
- TRUSTED_TYPES_POLICY configuration option must provide a "cr
- A configured TRUSTED_TYPES_POLICY callback (createHTML or cr
- TrustedTypes policy ' + policyName + ' could not be created.
- This browser does not support the [required] attribute for t
- This browser does not support the validity property for trix
AI-assisted analysis of basecamp/trix@4700401311 (2026-09-02).
Data as JSON: /api/errors/bc32767aa82bb2a9.
Report an issue: GitHub.