mjmlio/mjml · warning
[MJML] mj-include tags were found but includes are disabled
Error message
[MJML] mj-include tags were found but includes are disabled by default.\n Files: ${filesWithIgnoredIncludes.join(', ')}\n To enable includes, add --config.allowIncludes true to your command.\n See https://documentation.mjml.io/#mj-include for security notes. What it means
By default MJML disables mj-include processing for security reasons. When the CLI detects <mj-include> tags in the source input but includes were not enabled, it warns that those tags were ignored (left unprocessed) and output will not contain the included content.
Source
Thrown at packages/mjml-cli/src/client.js:350
// eslint-disable-next-line no-console
console.warn(
`[MJML] Some mj-include paths were denied because they are outside the allowed directories.\n` +
` Files: ${filesWithDeniedIncludes.join(', ')}\n` +
` Add the include directories to --config.includePath to allow them.\n` +
` See https://documentation.mjml.io/#mj-include for security notes.`,
)
}
}
// Warn when mj-include tags are present but includes are still ignored.
if (config.ignoreIncludes !== false) {
const MJ_INCLUDE_RE = /<mj-include\b/i
const filesWithIgnoredIncludes = inputs
.filter((i) => i && i.mjml && MJ_INCLUDE_RE.test(i.mjml))
.map((i) => i.file)
if (filesWithIgnoredIncludes.length) {
// eslint-disable-next-line no-console
console.warn(
`[MJML] mj-include tags were found but includes are disabled by default.\n` +
` Files: ${filesWithIgnoredIncludes.join(', ')}\n` +
` To enable includes, add --config.allowIncludes true to your command.\n` +
` See https://documentation.mjml.io/#mj-include for security notes.`,
)
}
}
failedStream.forEach(({ error, file }) => {
console.error(`${file ? `File: ${file}\n` : null}${error}`) // eslint-disable-line no-console
if (config.stack) {
console.error(error.stack) // eslint-disable-line no-console
}
})
if (inputOpt === 'v') {
const isInvalid =View on GitHub (pinned to 6c01d35af5)
Solutions
- Add --config.allowIncludes true to the mjml command to enable includes
- Then configure --config.includePath with the directories that may be included (see the related denied-includes warning)
- Or remove/replace the <mj-include> tags if includes are not wanted
- Pin/lock team build scripts so the flag is not lost when commands are copied
Example fix
// before mjml email.mjml // after mjml email.mjml --config.allowIncludes true --config.includePath ./partials
Defensive patterns
Strategy: validation
Validate before calling
const src = fs.readFileSync(input, 'utf8')
if (/<mj-include\b/i.test(src) && !allowIncludes) {
throw new Error('Input uses <mj-include>; run with --config.allowIncludes true')
} Type guard
const usesIncludes = (mjml) => typeof mjml === 'string' && /<mj-include\b/i.test(mjml)
Prevention
- Add --config.allowIncludes true wherever templates use mj-include
- Pre-scan inputs with /<mj-include\b/i before building
- Standardize the CLI invocation in a shared build script
- Note the flag in template-authoring guidelines
When it happens
Trigger: Running the mjml CLI on a file whose source matches /<mj-include\b/i without passing --config.allowIncludes true. No includePath check even runs; the includes are simply skipped.
Common situations: Upgrading MJML from a version where includes were on by default; copying templates that use mj-include into a build that never opted in; new team members unaware of the allowIncludes flag.
Related errors
- [MJML] Some mj-include paths were denied because they are ou
- [MJML security] includePath "${p}" is the root directory, wh
- Specified filePath does not exist
- Mixed variable syntax detected. Use either CSS property synt
- 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/9c1f51ddad4e3b45.
Report an issue: GitHub.