mjmlio/mjml · warning
[MJML] Some mj-include paths were denied because they are ou
Error message
[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. What it means
MJML's CLI scans the compiled HTML output of each input file for the sentinel comment '<!-- mj-include denied -->'. If found, it means some mj-include tags resolved to paths outside the directories allowed by includePath, and mjml-core replaced them with this denial marker instead of the included content. The CLI warns so the output is not silently missing included fragments.
Source
Thrown at packages/mjml-cli/src/client.js:333
failedStream.push({ file: i.file, error: e })
}
}
convertedStream.forEach((s) => {
if (get(s, 'compiled.errors.length')) {
console.error(map(s.compiled.errors, 'formattedMessage').join('\n')) // eslint-disable-line no-console
}
})
// Warn when includes were enabled but some include paths were denied (outside allowed roots).
if (config.ignoreIncludes === false) {
const DENIED_RE = /<!--\s*mj-include denied\s*-->/i
const filesWithDeniedIncludes = convertedStream
.filter((s) => s.compiled && s.compiled.html && DENIED_RE.test(s.compiled.html))
.map((s) => s.file)
if (filesWithDeniedIncludes.length) {
// 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` +View on GitHub (pinned to 6c01d35af5)
Solutions
- Add the directory containing the included files to the CLI config, e.g. mjml --config.includePath ./src/templates ./shared/templates input.mjml
- Change the mj-include paths so they resolve inside an allowed directory (relative paths within the project)
- Verify which files are affected via the 'Files:' list and inspect their compiled output for the denied marker
- If the includes are intentional and safe, explicitly enumerate only the needed folders rather than widening to a parent/root directory
Example fix
// before mjml templates/email.mjml // after mjml templates/email.mjml --config.includePath ./templates ./shared/partials
Defensive patterns
Strategy: validation
Validate before calling
const DENIED_RE = /<!--\s*mj-include denied\s*-->/i
const denied = files.filter(f => DENIED_RE.test(fs.readFileSync(f, 'utf8')))
if (denied.length) throw new Error(`Denied mj-include in: ${denied.join(', ')}`) Type guard
const hasDeniedIncludes = (html) => typeof html === 'string' && /<!--\s*mj-include denied\s*-->/i.test(html)
Prevention
- Always pass --config.includePath covering every folder containing included partials
- Keep mj-include paths relative to the templates directory
- Grep built HTML for 'mj-include denied' in CI
- Document required includePath in the repo build docs
When it happens
Trigger: Running the mjml CLI (packages/mjml-cli) on files containing <mj-include path="..." /> where the resolved path is outside the configured --config.includePath directories (or includePath is unset). The warning fires only when at least one compiled output matches DENIED_RE.
Common situations: CI builds after moving template files to a new directory; using absolute or ../ paths in mj-include; sharing templates across repos without extending includePath; upgrading MJML where includePath restrictions became stricter.
Related errors
- [MJML] mj-include tags were found but includes are disabled
- [MJML security] includePath "${p}" is the root directory, wh
- Specified filePath does not exist
- Malformed MJML. Check that your structure is correct and enc
- e.formattedMessage (compiled MJML errors printed via console
AI-assisted analysis of mjmlio/mjml@6c01d35af5 (2026-09-02).
Data as JSON: /api/errors/ceb009318f3a72a9.
Report an issue: GitHub.