mjmlio/mjml · error · Error
Mixed variable syntax detected. Use either CSS property synt
Error message
Mixed variable syntax detected. Use either CSS property syntax (e.g., color: {{variable}}) OR block syntax (e.g., {{variable}}), not both in the same document. What it means
sanitizeTemplateVariablesInHtml detects which template-variable style a document uses: CSS value/property syntax (color: {{var}}) or block syntax ({{var}} on its own). When both styles appear in the same document and allowMixedSyntax is not enabled, the library throws because the two styles require different sanitization passes that cannot be combined safely.
Source
Thrown at packages/mjml-core/src/index.js:410
}
const broken = detectBrokenTemplateDelimitersInCss(html, syntaxes)
if (broken.length) {
const details = broken
.map(
(b) => `${b.prefix}…${b.suffix} (${b.prefixCount} open, ${b.suffixCount} close)`,
)
.join(', ')
throw new Error(
`Unbalanced template delimiters found in CSS: ${details}. ${getTemplateDelimiterRecoveryMessage(contextName)}`,
)
}
const detected = detectVariableTypeInHtml(html, syntaxes)
result.isBlockVariable = detected.isBlockVariable
if (!allowMixedSyntax && result.isBlockVariable && (detected.isValueVariable || detected.isPropertyVariable)) {
throw new Error(
'Mixed variable syntax detected. Use either CSS property syntax (e.g., color: {{variable}}) OR block syntax (e.g., {{variable}}), not both in the same document.',
)
}
if (detected.isValueVariable) {
const sanitized = sanitizeCssValueVariablesHtml(html, syntaxes)
result.content = sanitized.result
result.variableMap = sanitized.variableMap
result.didSanitize = true
}
if (detected.isPropertyVariable) {
const sanitizedProp = sanitizeCssPropertyVariablesHtml(result.content, syntaxes)
result.content = sanitizedProp.result
result.propMap = sanitizedProp.propMap
result.didSanitize = true
}
View on GitHub (pinned to 6c01d35af5)
Solutions
- Rewrite the document to use a single variable style: convert inline 'color: {{var}}' usages to block syntax or vice versa.
- Pass allowMixedSyntax: true if mixed styles are intentional and safe for your pipeline.
- Split the document into separate MJML files, each using one style.
- Search the HTML for '{{' occurrences and normalize all placeholders with a codemod/lint rule.
Example fix
/* before: mixed */
{{bgColor}}
padding: {{padding}};
/* after: one style (block) */
{{bgColor}}
{{padding}}
/* or: pass { allowMixedSyntax: true } */ Defensive patterns
Strategy: validation
Validate before calling
function detectMixedSyntax(html) {
const block = /(^|\n)\s*\{\{\s*\w+\s*\}\}\s*(\n|$)/.test(html);
const value = /:\s*[^;{]*\{\{\s*\w+\s*\}\}/.test(html);
return block && value;
}
if (detectMixedSyntax(html)) throw new Error('Mixed template syntax in document'); Try / catch
try {
return sanitizeTemplateVariablesInHtml(html, opts)
} catch (e) {
if (e.message.startsWith('Mixed variable syntax')) {
console.error('Normalize placeholders to a single style:', e.message)
} else throw e
} Prevention
- Adopt one placeholder style per project and document it.
- Add a lint rule flagging inline 'property: {{var}}' when block style is standard.
- Review merged templates from multiple authors for style consistency.
When it happens
Trigger: Calling sanitizeTemplateVariablesInHtml (via sanitizationResult) on HTML where block-level '{{var}}' placeholders coexist with 'property: {{var}}' CSS usages while allowMixedSyntax is false/omitted.
Common situations: Merging email sections authored by different people or tools, one using block placeholders and the other inline CSS placeholders; copy-pasting snippets from two template styles into one MJML document.
Related errors
- Unbalanced template delimiters found in CSS: ${details}. ${g
- No type found for ${typeConfig}
- Parsing failed. Check your mjml.
- [MJML] mj-include tags were found but includes are disabled
- [MJML security] includePath "${p}" is the root directory, wh
AI-assisted analysis of mjmlio/mjml@6c01d35af5 (2026-09-02).
Data as JSON: /api/errors/0822bb475bcec244.
Report an issue: GitHub.