mjmlio/mjml · error · Error
An mj-head element add an unkown head attribute : ${attr} wi
Error message
An mj-head element add an unkown head attribute : ${attr} with params ${Array.isArray(params) ? params.join('') : params} What it means
During mjml2html, mj-head elements register attributes into globalData (fonts, styles, attributes, etc.). If an element passes an attribute (attr) that is not in the allowed head-attribute map, mjml2html throws this Error, naming the attribute and its params, and rendering aborts with no HTML output.
Source
Thrown at packages/mjml-core/src/index.js:795
if (Array.isArray(globalData[attr])) {
globalData[attr].push(...params)
} else if (Object.prototype.hasOwnProperty.call(globalData, attr)) {
if (params.length > 1) {
if (isObject(globalData[attr][params[0]])) {
globalData[attr][params[0]] = {
...globalData[attr][params[0]],
...params[1],
}
} else {
// eslint-disable-next-line prefer-destructuring
globalData[attr][params[0]] = params[1]
}
} else {
// eslint-disable-next-line prefer-destructuring
globalData[attr] = params[0]
}
} else {
throw Error(
`An mj-head element add an unkown head attribute : ${attr} with params ${
Array.isArray(params) ? params.join('') : params
}`,
)
}
},
}
globalData.headRaw = processing(mjHead, headHelpers)
content = processing(mjBody, bodyHelpers, applyAttributes)
if (!content) {
throw new Error(
'Malformed MJML. Check that your structure is correct and enclosed in <mjml> tags.',
)
}
View on GitHub (pinned to 6c01d35af5)
Solutions
- Correct the head element/attribute name in the template to a supported one (mj-attributes, mj-style, mj-font, mj-breakpoint, mj-preview, mj-title)
- Register the custom component so its head attributes are known to mjml-core
- Check the attribute and params values in the message to pinpoint the offending tag
- Align MJML package versions (mjml-core vs custom components) so registered attributes match the template
Example fix
// before <mj-head><mj-titel>Hi</mj-titel></mj-head> // typo, throws // after <mj-head><mj-title>Hi</mj-title></mj-head>
Defensive patterns
Strategy: try-catch
Validate before calling
const ALLOWED_HEAD = new Set(['mj-attributes','mj-style','mj-font','mj-breakpoint','mj-preview','mj-title'])
for (const child of head.children) {
if (!ALLOWED_HEAD.has(child.tagName)) throw new Error(`Unknown head element: ${child.tagName}`)
} Type guard
const isKnownHeadAttr = (attr, known) => typeof attr === 'string' && known.has(attr)
Try / catch
try {
const { html, errors } = mjml2html(mjml)
} catch (e) {
if (String(e.message).startsWith('An mj-head element add an unkown head attribute')) {
// surface the attribute name from e.message and fail fast with a clear template error
}
throw e
} Prevention
- Check head tag spelling (mj-title, mj-preview, mj-style, etc.)
- Register custom components before rendering templates that use them
- Keep mjml-core and custom component versions in sync
- Lint MJML templates against the set of registered head attributes
When it happens
Trigger: Rendering a template containing an mj-head child (or custom component) that calls the head attribute handler with an unregistered attr — e.g. a typo like <mj-fonts>, an unknown/custom head element, or a component emitting an attribute not registered via registerComponent's head handling.
Common situations: Typos in head tags; custom components added to mj-head without registering their head attributes; version mismatches where a head attribute was renamed/removed; copying templates between MJML versions.
Related errors
- dependency "tag" must be of type string
- "dependencies" must be an object.
- "dependencies" option should be provided to mjml validator
- ValidationError: \n ${errors.map((e) => e.formattedMessage).
- Malformed MJML. Check that your structure is correct and enc
AI-assisted analysis of mjmlio/mjml@6c01d35af5 (2026-09-02).
Data as JSON: /api/errors/2b86a8051e90ee23.
Report an issue: GitHub.