basecamp/trix · error · TypeError
TRUSTED_TYPES_POLICY configuration option must provide a "cr
Error message
TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.
What it means
Companion check to the createHTML requirement: when a TRUSTED_TYPES_POLICY is supplied in the config, DOMPurify also requires a createScriptURL function. The policy is used to sign both HTML output and script URLs (e.g. for allowed src attributes), so a missing createScriptURL would leave script URL sinks unsigned or unsafe. DOMPurify throws this TypeError at configuration time, fail-closed.
Source
Thrown at action_text-trix/app/assets/javascripts/trix.js:2654
}
/* 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) {
// Explicit opt-out for this call: perform no Trusted Types signing and
// create nothing (so a strict `trusted-types` CSP that disallows a
// `dompurify` policy can still call `sanitize` from inside its ownView on GitHub (pinned to 4700401311)
Solutions
- Add a createScriptURL function to the policy object (an identity or allow-list-based signer is fine).
- Verify the key spelling is exactly createScriptURL.
- If you never load scripts from sanitized content, still supply a strict createScriptURL that throws or returns only known-safe URLs.
- Prefer trustedTypes.createPolicy(name, {createHTML, createScriptURL}) so both methods always exist.
Example fix
// before
DOMPurify.sanitize(dirty, { TRUSTED_TYPES_POLICY: { createHTML: (s) => s } });
// after
DOMPurify.sanitize(dirty, {
TRUSTED_TYPES_POLICY: {
createHTML: (s) => s,
createScriptURL: (url) => ALLOWED_URLS.includes(url) ? url : 'about:blank'
}
}); Defensive patterns
Strategy: type-guard
Validate before calling
if (cfg.TRUSTED_TYPES_POLICY && typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {
throw new Error('Refusing to configure: TRUSTED_TYPES_POLICY.createScriptURL is missing');
} Type guard
const hasCreateScriptURL = (p) => !!p && typeof p.createScriptURL === 'function';
Try / catch
try {
DOMPurify.sanitize(dirty, { TRUSTED_TYPES_POLICY: policy });
} catch (e) {
if (String(e.message).includes('createScriptURL')) {
console.error('Supplied policy lacks createScriptURL; fix policy object.');
} else { throw e; }
} Prevention
- Supply both hooks even if scripts are irrelevant; use a strict createScriptURL that rejects unknown URLs.
- Build policies via trustedTypes.createPolicy so both methods are declared together.
- Check key spelling: createScriptURL (capital URL).
- Add a unit test asserting the policy object satisfies both typeof checks before configuration.
When it happens
Trigger: DOMPurify.sanitize(dirty, { TRUSTED_TYPES_POLICY: { createHTML: fn } }) — a policy object providing only createHTML, or a natively created policy object whose createScriptURL is absent or not a function.
Common situations: Copy-pasting a minimal policy example that only handles HTML; building a policy for a browser where you thought script URLs were irrelevant but DOMPurify still validates both; property name typos (createScriptUrl).
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/80d72df931414098.
Report an issue: GitHub.