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

  1. Log/inspect the exact string passed to the parser; confirm it is non-empty well-formed XML/MJML.
  2. Fix unclosed or mismatched tags in the source document.
  3. Disable or fix custom preprocessors that may be corrupting the XML before parsing.
  4. 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

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


AI-assisted analysis of mjmlio/mjml@6c01d35af5 (2026-09-02). Data as JSON: /api/errors/d5d0d976dfcc28b9. Report an issue: GitHub.