GoogleChrome/lighthouse · error
Ctc messages cannot contain double dollar: ${icu.message}
Error message
Ctc messages cannot contain double dollar: ${icu.message} What it means
Thrown by _ctcValidityChecks() when a converted CTC (CTC = internal canonical format) message contains `$$` (double dollar). In CTC format, placeholders are delimited by `$...$`, so an empty `$...$` pair (i.e. `$$`) is always invalid — it implies a placeholder with no name, which cannot be resolved or translated.
Source
Thrown at core/scripts/i18n/collect-strings.js:436
};
}
icu.message = tempMessage;
}
/**
* Do some basic checks on a ctc object to confirm that it is valid. Future
* ctc regression catching should go here.
*
* @param {IncrementalCtc} icu the ctc output message to verify
*/
function _ctcValidityChecks(icu) {
// '$$' i.e. "Double Dollar" is always invalid in ctc.
const regex = /\$([^$]*?)\$/g;
const matches = regex.exec(icu.message);
if (Array.isArray(matches)) {
matches.forEach(function(value) {
if (!value) {
throw new Error(`Ctc messages cannot contain double dollar: ${icu.message}`);
}
});
}
}
/**
* Take a series of messages and apply ĥât̂ markers to the translatable portions
* of the text. Used to generate `en-XL` locale to debug i18n strings. This is
* done while messages are in `ctc` format, and therefore modifies only the
* messages themselves while leaving placeholders untouched.
*
* @param {Record<string, CtcMessage>} messages
* @return {Record<string, CtcMessage>}
*/
function createPsuedoLocaleStrings(messages) {
/** @type {Record<string, CtcMessage>} */
const psuedoLocalizedStrings = {};
for (const [key, ctc] of Object.entries(messages)) {View on GitHub (pinned to 9515cd4e58)
Solutions
- Inspect the source LHL message that produced the CTC output and ensure all ICU placeholders are well-formed and non-empty.
- If this appears after a code change to the conversion logic, debug convertMessageToCtc for the specific message.
- Ensure no literal `$` characters exist in source messages, or escape them per the project's convention.
Defensive patterns
Strategy: validation
Validate before calling
function ctcHasDoubleDollar(message) {
const re = /\$([^$]*?)\$/g;
let m;
while ((m = re.exec(message))) {
if (!m[1]) return true; // empty capture means $$ found
}
return false;
} Prevention
- Never include literal '$' characters in source LHL messages.
- After converting to CTC, always run _ctcValidityChecks in a test.
- If a placeholder name is empty or undefined, fix it before conversion.
When it happens
Trigger: A converted message ends up with adjacent `$` delimiters producing `$$`, usually from a conversion bug or a source message that had degenerate placeholder usage.
Common situations: Bugs in convertMessageToCtc; source LHL messages with empty or adjacent ICU placeholders that collapse to `$$` after conversion; manual edits to generated CTC output.
Related errors
- must use same format and formatType for a given name. Invali
- string collision: `message` and `description` are the same b
- unsupported JSDoc comment: ${JSON.stringify(comment)}
- Incorrectly formatted @example: "${rawExample}"
- [${err.message}] Did not find the expected syntax in message
AI-assisted analysis of GoogleChrome/lighthouse@9515cd4e58 (2026-08-13).
Data as JSON: /api/errors/a9d51f0c64812830.
Report an issue: GitHub.