Foundry376/Mailspring · error
ComposerEditor: ${reason}, inserting empty paragraph to reco
Error message
ComposerEditor: ${reason}, inserting empty paragraph to recover. What it means
Self-healing warning in ComposerEditor.onChange: the incoming Slate value was structurally broken (reason is filled in by the check that fired), so a recovery operation — inserting an empty div paragraph at path [0] — is applied directly to the value before it reaches the parent, producing one clean onChange instead of a broken one plus a deferred fix.
Source
Thrown at app/src/components/composer-editor/composer-editor.tsx:349
};
onChange = (change: { operations: Immutable.List<Operation>; value: Value }) => {
// This needs to be here because some composer plugins defer their calls to onChange
// (like spellcheck and the context menu).
if (!this._mounted) return;
// If the incoming value is broken, apply recovery operations directly to `value`
// before forwarding to the parent. This emits a single onChange with the already-
// corrected value rather than emitting the broken value and then a second onChange
// from a deferred microtask (which is what would happen if we called editor commands
// here). The parent therefore never sees the broken state, and any recovery operation
// that changes the document is included in the operations list so the parent knows
// the document changed and doesn't skip saving.
let { operations, value } = change;
const reason = getDocumentBrokenReason(value);
if (reason) {
console.warn(`ComposerEditor: ${reason}, inserting empty paragraph to recover.`);
const op = require('slate').Operation.create({
type: 'insert_node',
path: Immutable.List([0]),
node: Block.create({ type: 'div', nodes: Immutable.List([Text.create('')]) }),
});
operations = operations.push(op);
value = op.apply(value);
}
// Same idea as above, but for a broken selection rather than a broken document: move
// the dangling anchor/focus back to the start of the document so the next keystroke
// doesn't crash inside Slate. This check must run on `value` (which may have just been
// repaired above), not the original `change.value` — removing the last text-carrying
// node from the document unsets the selection *and* triggers the document-broken repair
// in the same change, and inserting the recovery paragraph does not re-anchor a
// previously-unset selection point, so the selection would still be broken afterwards.
if (isSelectionBroken(value, change.operations)) {
console.warn(View on GitHub (pinned to 648c685d60)
Solutions
- No manual fix needed — the editor repairs the document automatically
- If it recurs, identify the plugin/plugin-paste producing invalid Slate nodes and fix its serializer
Defensive patterns
Strategy: fallback
When it happens
Trigger: Thrown at app/src/components/composer-editor/composer-editor.tsx:349 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of Foundry376/Mailspring@648c685d60 (2026-09-03).
Data as JSON: /api/errors/3ec823985cb016de.
Report an issue: GitHub.