{"record":{"id":"a9d51f0c64812830","repo":"GoogleChrome/lighthouse","slug":"ctc-messages-cannot-contain-double-dollar-icu-m","errorCode":null,"errorMessage":"Ctc messages cannot contain double dollar: ${icu.message}","messagePattern":"Ctc messages cannot contain double dollar: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/scripts/i18n/collect-strings.js","lineNumber":436,"sourceCode":"    };\n  }\n  icu.message = tempMessage;\n}\n\n/**\n * Do some basic checks on a ctc object to confirm that it is valid. Future\n * ctc regression catching should go here.\n *\n * @param {IncrementalCtc} icu the ctc output message to verify\n */\nfunction _ctcValidityChecks(icu) {\n  // '$$' i.e. \"Double Dollar\" is always invalid in ctc.\n  const regex = /\\$([^$]*?)\\$/g;\n  const matches = regex.exec(icu.message);\n  if (Array.isArray(matches)) {\n    matches.forEach(function(value) {\n      if (!value) {\n        throw new Error(`Ctc messages cannot contain double dollar: ${icu.message}`);\n      }\n    });\n  }\n}\n\n/**\n * Take a series of messages and apply ĥât̂ markers to the translatable portions\n * of the text.  Used to generate `en-XL` locale to debug i18n strings. This is\n * done while messages are in `ctc` format, and therefore modifies only the\n * messages themselves while leaving placeholders untouched.\n *\n * @param {Record<string, CtcMessage>} messages\n * @return {Record<string, CtcMessage>}\n */\nfunction createPsuedoLocaleStrings(messages) {\n  /** @type {Record<string, CtcMessage>} */\n  const psuedoLocalizedStrings = {};\n  for (const [key, ctc] of Object.entries(messages)) {","sourceCodeStart":418,"sourceCodeEnd":454,"githubUrl":"https://github.com/GoogleChrome/lighthouse/blob/9515cd4e58ebed69f78742d932b501c2cab8ad8f/core/scripts/i18n/collect-strings.js#L418-L454","documentation":"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.","triggerScenarios":"A converted message ends up with adjacent `$` delimiters producing `$$`, usually from a conversion bug or a source message that had degenerate placeholder usage.","commonSituations":"Bugs in convertMessageToCtc; source LHL messages with empty or adjacent ICU placeholders that collapse to `$$` after conversion; manual edits to generated CTC output.","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"function ctcHasDoubleDollar(message) {\n  const re = /\\$([^$]*?)\\$/g;\n  let m;\n  while ((m = re.exec(message))) {\n    if (!m[1]) return true; // empty capture means $$ found\n  }\n  return false;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["i18n","ctc","placeholder","collect-strings","internal-format"],"backgroundTag":null,"analyzedSha":"9515cd4e58ebed69f78742d932b501c2cab8ad8f","analyzedAt":"2026-08-13T06:28:10.346Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}