Diagnostics
Use diagnostic codes to investigate document, editing, review, font, and collaboration failures.
The editor reports diagnostics for document opening, editing, review, fonts, and collaboration. Failure diagnostics carry stable codes. Look up a code to get a fixed hint with its cause and recommended action.
Diagnostics never contain document content. The editor builds them from closed lists of codes, booleans, and bucketed numbers. Document text, part names, relationship targets, author names, and font names are never included. You can export these fields to an error tracker or metrics backend. Review any attributes that you add and any data your SDK collects. For more information, see Privacy review checklist.
Receive diagnostics
Register a module with an onDiagnostic listener to receive diagnostics from the initial document open. The editor opens that document before your code can call editor.on.
import { DocxEditor } from '@docx-editor.dev/react';
import { explainDiagnostic, type EditorDiagnostic, type EditorModule } from '@docx-editor.dev/core';
// Create the module once, outside the component. The editor reads modules only at creation.
const diagnostics: EditorModule = {
id: 'diagnostics',
onDiagnostic: (event: EditorDiagnostic) => {
if (event.kind === 'edit.rejected') {
console.warn(event.code, explainDiagnostic(event.code).hint);
}
},
};
const MODULES = [diagnostics];
export function Editor({ bytes }: { bytes: Uint8Array }) {
return <DocxEditor document={bytes} modules={MODULES} />;
}After the editor exists, you can also subscribe with editor.on('diagnostic', listener). Both receive the same events. A listener that throws doesn't affect the editor.
Diagnostic kinds
Switch on kind to narrow the event. Every event also has schemaVersion, editorSessionId, and time. Each editor instance generates a random editorSessionId and does not persist it. Use it to connect diagnostics from the same instance.
| Kind | When | Fields |
|---|---|---|
document.open | A document opened or failed to open. | outcome (opened or rejected), sizeBucket, and pagesBucket and durationMs when opened, or code and the failure detail when rejected. A headless host doesn't paginate, so it omits pagesBucket. An opened document also has shape, with part, paragraph, review item, and embedded font buckets. |
edit.rejected | An edit, a command, or a tracked change was refused. | code, origin (command, input, or automation), tracked, command for a refused exec call, and the failure detail. |
review.skipped | Accepting, rejecting, or reassigning tracked changes skipped some of them. | code, count, and the failure detail: operation, changeKind, formattingKind, and part. |
font.failed | A font did not load, and the editor used a substitute. | code. |
history | An undo step did not group as the gesture intended. Informational. | code. |
custom-node | A custom node payload in the document could not be read. The node name is not included. | code. |
collab.status | A collaboration session joined, disconnected, failed, or healed. | status, previous, recovering, and code when something is wrong. The first ready includes connectMs only when the editor observed the wait. |
collab.participants | The number of people in the room changed. | count, this editor included. |
performance | The editor summarizes timings after a minute, when the page becomes hidden, or when the editor closes. | windowMs, optional pagesBucket, and optional interaction, layout, and paint summaries. Slow interactions also include code. See Measure performance. |
Document sizes and counts use buckets, such as 4-8MiB or 10-99. Rare combinations can still distinguish documents within an organization. The telemetry package omits detailed shape buckets by default.
Failure detail
A code identifies the failure. Optional detail fields identify the engine condition and where it occurred. These fields use closed lists and help you investigate without document content.
| Field | On | What it holds |
|---|---|---|
cause | document.open, edit.rejected, review.skipped | The engine's own reason, such as undeclared-prefix under open.xml-malformed, split-not-clean under edit.unmapped-change, or unaddressed (a change with no w:id or author) under review.revision-unsupported. For an error the engine did not expect, exception. |
errorName | document.open, edit.rejected | The class of the exception when cause is exception, such as TypeError. The message is never included, because it can quote the document. |
stage | document.open, edit.rejected | Where an exception was caught: open-mount, open-layout, command, review-item (accept or reject from a review card), or automation (an editing API batch). |
part | document.open, review.skipped | The role of the package part, such as main-document, header, footnotes, or relationships, never its name. A part under a nonstandard name reports other. |
operation | review.skipped | accept, reject, or reassign. |
changeKind | review.skipped | The kind of the skipped change: insert, delete, replace, moveFrom, moveTo, format, paragraphMark, or structural. |
formattingKind | review.skipped | For a formatting change, its property change, such as rPrChange or tblGridChange. Any other element reports other. |
Use code for application logic. Use cause for investigation, because these internal reasons can change between versions. To list every cause, call diagnosticCauses().
An open that throws reports open.failed with cause: 'exception', and a command, a review card action, or an editing API batch that throws reports edit.internal-invariant with cause: 'exception'. The error still reaches your code as before. An exception from your own code inside run() is not reported.
These examples show a malformed header and a skipped formatting change:
{ "kind": "document.open", "outcome": "rejected", "code": "open.xml-malformed",
"cause": "undeclared-prefix", "part": "header", "sizeBucket": "64-128KiB" }
{ "kind": "review.skipped", "code": "review.revision-unsupported", "count": 3,
"operation": "accept", "changeKind": "format", "formattingKind": "tblGridChange",
"part": "main-document" }When you report a problem, include the code, the failure detail, and the engineVersion that your telemetry adds. A refusal's cause names the engine condition that refused it. An exception's errorName and stage say what kind of error it was and where it was caught; they do not include a stack trace.
Codes
Codes are stable. New codes can be added, but existing codes are never renamed. To get the hint for a code in your own code, call explainDiagnostic(code). To get the code for the local refusal message in snapshot().lastRejection, call diagnosticCodeOfRefusal(reason).
Open
Edit
Review
Font
History
Custom nodes
Performance
A performance event summarizes how fast the editor responded during a window. It carries a code only when the summary needs attention.
Collaboration
A collaboration code is collab. followed by the session's own failure code. It appears on collab.status events. An edit that a session refuses is an edit.rejected event with an edit.collaboration-* code instead, so the collab.collaboration-session-* and collab.collaboration-text-limit codes appear only when a session reports them as its status reason.