mjmlio/mjml · warning
e.formattedMessage (compiled MJML errors printed via console
Error message
e.formattedMessage (compiled MJML errors printed via console.warn)
What it means
Not a thrown error but a diagnostic output path: in watchFiles' readAndCompile, when mjml2html returns compiled.errors, each error's formattedMessage is printed via console.warn so watch-mode users see validation/parse warnings with file/line context while compilation continues. The file is still written if outputToFile succeeds; warnings indicate issues without aborting the watch loop.
Source
Thrown at packages/mjml-cli/src/commands/watchFiles.js:62
watcher.add(difference(files.toWatch, files.watched))
watcher.unwatch(difference(files.watched, files.toWatch))
/* eslint-enable no-use-before-define */
}
const readAndCompile = async (file) => {
const { config } = options
const beautify = config.beautify && config.beautify !== 'false'
const minify = config.minify && config.minify !== 'false'
const content = readFile(file).mjml
const compiled = await mjml2html(content, {
...config,
beautify,
minify,
filePath: file,
actualPath: file,
})
compiled.errors.forEach((e) => console.warn(e.formattedMessage))
try {
await outputToFile({ file, compiled })
console.log(`${file} - Successfully compiled`)
} catch (e) {
console.log(`${file} - Error while compiling file`)
}
}
const watcher = chokidar
.watch(input.map((i) => i.replace(/\\/g, '/')))
.on('change', (file) => synchronyzeWatcher(path.resolve(file)))
.on('add', (file) => {
const filePath = path.resolve(file)
console.log(`Now watching file: ${filePath}`)
const matchInputOption = input.reduce(
(found, file) =>View on GitHub (pinned to 6c01d35af5)
Solutions
- Read each printed formattedMessage; fix the reported file/line so warnings disappear on the next save.
- Ignore transient warnings during rapid successive saves; re-save once editing is complete.
- Harden the watch pipeline by validating files (mjml --validate or validationLevel checks) before output.
- If warnings should block output, wrap compilation and check compiled.errors before calling outputToFile.
Example fix
// before: compile and always output
compiled.errors.forEach((e) => console.warn(e.formattedMessage))
await outputToFile({ file, compiled })
// after: optionally skip output on errors
if (compiled.errors.length) {
compiled.errors.forEach((e) => console.warn(e.formattedMessage))
return // skip writing broken output
}
await outputToFile({ file, compiled }) Defensive patterns
Strategy: try-catch
Validate before calling
const fs = require('fs');
if (!fs.existsSync(file)) { console.error(`Watched file vanished: ${file}`); return; }
if (!fs.readFileSync(file, 'utf8').trim()) { console.warn(`Skipped empty file: ${file}`); return; } Try / catch
const compiled = mjml2html(source, { beautify, minify, filePath: file })
if (compiled.errors.length) {
compiled.errors.forEach((e) => console.warn(e.formattedMessage))
// decide: continue writing (warn-only) or return to block output
}
try {
await outputToFile({ file, compiled })
} catch (e) {
console.error(`${file} - output failed:`, e.message)
} Prevention
- Treat formattedMessage output as a signal to fix templates, not noise.
- Add editor linting for MJML so errors are caught before saving.
- Consider gating watch output on compiled.errors.length in strict pipelines.
When it happens
Trigger: Running `mjml --watch` on a directory while a watched file contains validation errors (unknown components, bad attributes) or recoverable parse issues — mjml2html returns an errors array which readAndCompile prints line by line.
Common situations: Live-editing templates in an editor and saving intermediate broken states; auto-formatters introducing invalid attributes; partial files being written while the watcher compiles them mid-save.
Related errors
- Specified filePath does not exist
- ValidationError: \n ${errors.map((e) => e.formattedMessage).
- No type found for ${typeConfig}
- [MJML] Some mj-include paths were denied because they are ou
- [MJML] mj-include tags were found but includes are disabled
AI-assisted analysis of mjmlio/mjml@6c01d35af5 (2026-09-02).
Data as JSON: /api/errors/42092f2b8f200780.
Report an issue: GitHub.