{"record":{"id":"d5d0d976dfcc28b9","repo":"mjmlio/mjml","slug":"parsing-failed-check-your-mjml","errorCode":null,"errorMessage":"Parsing failed. Check your mjml.","messagePattern":"Parsing failed\\. Check your mjml\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/mjml-parser-xml/src/index.js","lineNumber":451,"sourceCode":"        }\n      },\n    },\n    {\n      recognizeCDATA: true,\n      decodeEntities: false,\n      recognizeSelfClosing: true,\n      lowerCaseAttributeNames: false,\n    },\n  )\n\n  // Apply preprocessors to raw xml\n  xml = flow(preprocessors)(xml)\n\n  parser.write(xml)\n  parser.end()\n\n  if (!isObject(mjml)) {\n    throw new Error('Parsing failed. Check your mjml.')\n  }\n\n  cleanNode(mjml)\n\n  // Assign \"attributes\" property if not set\n  if (addEmptyAttributes) {\n    setEmptyAttributes(mjml)\n  }\n\n  if (cssIncludes.length) {\n    const head = find(mjml.children, { tagName: 'mj-head' })\n\n    if (head) {\n      if (head.children) {\n        head.children = [...head.children, ...cssIncludes]\n      } else {\n        head.children = cssIncludes\n      }","sourceCodeStart":433,"sourceCodeEnd":469,"githubUrl":"https://github.com/mjmlio/mjml/blob/6c01d35af5da14108b86bbf052232e99de7ca755/packages/mjml-parser-xml/src/index.js#L433-L469","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: empty/garbage input\nmjml2html(await fs.readFile(p, 'utf16le')) // mangled encoding\n// after\nconst xml = await fs.readFile(p, 'utf8')\nif (!xml.trim()) throw new Error('empty template')\nmjml2html(xml)","handlingStrategy":"validation","validationCode":"function assertParseableMjml(src) {\n  if (typeof src !== 'string' || !src.trim()) throw new Error('Empty MJML input');\n  if (!/^[\\s\\S]*</.test(src)) throw new Error('Input is not XML/MJML');\n}","typeGuard":null,"tryCatchPattern":"try {\n  return mjml2html(raw)\n} catch (e) {\n  if (e.message === 'Parsing failed. Check your mjml.') {\n    console.error('Input was not parseable. First 200 chars:', String(raw).slice(0, 200))\n  } else throw e\n}","preventionTips":["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."],"tags":["parser","xml","syntax","empty-input"],"backgroundTag":"xml-parse-error","analyzedSha":"6c01d35af5da14108b86bbf052232e99de7ca755","analyzedAt":"2026-09-02T21:31:03.649Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}