Appearance
11. Error Handling & Recovery
11.1 Principles
MdFlow is a rendering-layer standard. Errors in plugin code, custom elements, or malformed input MUST NOT terminate the pipeline or produce an unrenderable state. The specification's default behavior is graceful degradation: the offending span becomes inert text or a sentinel node, and subsequent source continues to parse and render.
11.2 Error classes
The specification distinguishes three error classes:
- Input errors. Source text that does not match any recognized construct. These are not errors in the implementation; source MAY contain arbitrary bytes and the implementation MUST produce an output for every input. Unrecognized inline sequences fall through to
Textnodes. - Plugin errors. A plugin throws or returns a malformed token during parsing, or a malformed DOM operation during rendering. Plugin errors MUST be caught; the pipeline MUST continue.
- Host errors. DOM APIs throw (e.g., due to host-imposed CSP). These errors propagate to the caller only after the pipeline has emitted a diagnostic sentinel.
11.3 Error shape
Implementations SHOULD expose caught errors via a single error object shape:
MdFlowError {
kind: 'plugin' | 'host' | 'internal',
plugin: string?, // name of the offending plugin, if any
phase: 'tokenize' | 'parse-inline' | 'diff' | 'render',
message: string,
source: { line: integer, column: integer }?,
cause: Error?
}The kind, phase, and message fields are REQUIRED. Others are OPTIONAL.
11.4 Recovery behavior
11.4.1 Plugin tokenize error
If a plugin throws during tokenization of a region R:
REQ-ERR-1. The implementation MUST catch the error. REQ-ERR-2. The bytes of R up to and including the failing byte MUST be committed as a Text token (or merged into an adjacent Paragraph, per inline rules). REQ-ERR-3. Tokenization MUST resume at the byte following R. REQ-ERR-4. The plugin MAY be disabled for the remainder of the source, at the implementation's discretion.
11.4.2 Plugin render error
If a plugin throws during rendering of a token:
REQ-ERR-5. The implementation MUST emit a sentinel DOM node in place of the plugin's output. The sentinel MUST:
- be a
<span>with classmdflow-erroranddata-mdflow-error-phase="render", - contain
textContentequal to the raw source slice of the token, - be semantically a leaf (no children).
REQ-ERR-6. The pipeline MUST continue with the next token.
11.4.3 Host DOM error
If a DOM API throws during rendering:
REQ-ERR-7. The error MUST be logged via the error observer (if registered) and re-thrown to the push() / flush() caller.
REQ-ERR-8. DOM state MUST remain consistent with the subset of tokens rendered before the error. Partially-applied operations MUST be rolled back at the element level (i.e., incomplete nodes removed) before re-throwing.
11.5 Error observer
A conforming implementation SHOULD allow registering a single error observer callback:
onError(error: MdFlowError) → voidObservers MUST NOT affect pipeline state. Observer exceptions MUST be caught and discarded.
11.6 Pipeline state after error
After any caught plugin error, the pipeline state MUST be consistent such that subsequent push() and flush() calls behave as if the offending region were replaced by a Text token of the same byte range. In particular, all invariants in §3.4.5 MUST continue to hold.
11.7 Stream termination
flush() MUST be callable after any number of caught errors. It MUST finalize all pending tokens per §5.5 and MUST NOT throw due to previously-observed errors.
11.8 Security-related errors
A source span that would violate the §10 Security Model (e.g., an attempt to register a non-whitelisted custom element) is NOT an error — it is a normative parse outcome producing a Text node or an inert fallback. Security filters MUST NOT throw; they MUST clip or replace and continue.
11.9 Developer diagnostics
Implementations MAY provide a strict mode that re-throws caught errors for debugging. Strict mode is OPTIONAL and MUST NOT be the default.