mjmlio/mjml · critical · Error
Parsing failed. Check your mjml.
Error message
Parsing failed. Check your mjml.
What it means
After feeding the preprocessed XML into the sax parser, MJMLParser checks that a parsed object tree (mjml) was actually produced. If the result is not an object — nothing was parsed or the root never materialized — it throws 'Parsing failed. Check your mjml.' indicating the input was not parseable XML/MJML at all.
Source
Thrown at packages/mjml-parser-xml/src/index.js:451
}
},
},
{
recognizeCDATA: true,
decodeEntities: false,
recognizeSelfClosing: true,
lowerCaseAttributeNames: false,
},
)
// Apply preprocessors to raw xml
xml = flow(preprocessors)(xml)
parser.write(xml)
parser.end()
if (!isObject(mjml)) {
throw new Error('Parsing failed. Check your mjml.')
}
cleanNode(mjml)
// Assign "attributes" property if not set
if (addEmptyAttributes) {
setEmptyAttributes(mjml)
}
if (cssIncludes.length) {
const head = find(mjml.children, { tagName: 'mj-head' })
if (head) {
if (head.children) {
head.children = [...head.children, ...cssIncludes]
} else {
head.children = cssIncludes
}View on GitHub (pinned to 6c01d35af5)
Solutions
- Log/inspect the exact string passed to the parser; confirm it is non-empty well-formed XML/MJML.
- Fix unclosed or mismatched tags in the source document.
- Disable or fix custom preprocessors that may be corrupting the XML before parsing.
- Check file reading/fetch steps for encoding errors that yield empty or binary content.
Example fix
// before: empty/garbage input
mjml2html(await fs.readFile(p, 'utf16le')) // mangled encoding
// after
const xml = await fs.readFile(p, 'utf8')
if (!xml.trim()) throw new Error('empty template')
mjml2html(xml) Defensive patterns
Strategy: validation
Validate before calling
function assertParseableMjml(src) {
if (typeof src !== 'string' || !src.trim()) throw new Error('Empty MJML input');
if (!/^[\s\S]*</.test(src)) throw new Error('Input is not XML/MJML');
} Try / catch
try {
return mjml2html(raw)
} catch (e) {
if (e.message === 'Parsing failed. Check your mjml.') {
console.error('Input was not parseable. First 200 chars:', String(raw).slice(0, 200))
} else throw e
} Prevention
- Verify file reads/fetches return non-empty UTF-8 content.
- Test custom preprocessors against well-formed XML.
- Fail fast on empty inputs before invoking the parser.
When it happens
Trigger: Calling MJMLParser (or mjmlJson/partialMjml/mjml2html) with empty input, non-XML content (raw HTML with unclosed tags the parser cannot recover from, JSON, binary), or input mangled by a preprocessor into invalid XML.
Common situations: Reading a file with wrong encoding producing garbage; passing an HTML fragment rather than MJML; a custom preprocessor regex replacing the root tag; empty string from a failed fetch/read step in a build script.
Related errors
- Unbalanced template delimiters found in CSS: ${details}. ${g
- Mixed variable syntax detected. Use either CSS property synt
- Specified filePath does not exist
- Circular inclusion detected on file : ${partialPath}
AI-assisted analysis of mjmlio/mjml@6c01d35af5 (2026-09-02).
Data as JSON: /api/errors/d5d0d976dfcc28b9.
Report an issue: GitHub.