hcengineering/platform · error
No valid diff possible applying ${op.path} ${JSON.stringify(
Error message
No valid diff possible applying ${op.path} ${JSON.stringify(error, undefined, 2)} What it means
recreateChangeContentSteps replays an editor diff by applying ProseMirror operations one at a time; when an operation throws, it shifts to the next queued op and retries, but if the op queue is exhausted it throws this error including the failing op path and the underlying error JSON. It means the recorded change set cannot be validly applied to the document (documents diverged beyond what the diff can bridge).
Source
Thrown at plugins/text-editor-resources/src/components/diff/recreate.ts:196
const afterStepJSON = clone(this.currentDoc) // working document receiving patches
const pathParts = op.path.split('/')
// collect operations until we receive a valid document:
// apply ops-patches until a valid prosemirror document is retrieved,
// then try to create a transformation step or retry with next operation
while (toDoc == null) {
applyPatch(afterStepJSON, [op])
try {
toDoc = this.schema.nodeFromJSON(afterStepJSON)
toDoc.check()
} catch (error: any) {
toDoc = null
if (this.ops.length > 0) {
op = this.ops.shift() as Operation
ops.push(op)
} else {
throw new Error(`No valid diff possible applying ${op.path} ${JSON.stringify(error, undefined, 2)}`)
}
}
}
// apply operation (ignoring afterStepJSON)
if (ops.length === 1 && (pathParts.includes('attrs') || pathParts.includes('type'))) {
// Node markup is changing
this.addSetNodeMarkup() // a lost update is ignored
ops = []
} else if (ops.length === 1 && op.op === 'replace' && pathParts[pathParts.length - 1] === 'text') {
// Text is being replaced, we apply text diffing to find the smallest possible diffs.
this.addReplaceTextSteps(op, afterStepJSON)
ops = []
} else if (this.addReplaceStep(toDoc, afterStepJSON)) {
// operations have been applied
ops = []
}
}View on GitHub (pinned to 63e28dc964)
Solutions
- Log op.path and the wrapped error to identify the first path that no longer matches the document schema
- Recreate the diff between the actual current doc and target doc instead of replaying the stale one
- Update the editor schema/migrations so legacy node types and attrs referenced by the ops still resolve
- Guard the call site (init) with try-catch and fall back to re-rendering the document rather than crashing the editor
Example fix
// before
try {
await recreateChangeContentSteps(doc, change)
} catch (e) { throw e }
// after
try {
await recreateChangeContentSteps(doc, change)
} catch (e) {
console.error('Diff replay failed, rebuilding diff from live doc', e)
await rebuildDiffFromDocs(currentDoc, targetDoc)
} Defensive patterns
Strategy: try-catch
Validate before calling
function opPathsExistInSchema (ops: Operation[], schema: Schema): boolean {
return ops.every((op) => {
const parts = op.path.split('.')
return parts.every((p) => p in schema.nodes || p in schema.marks || ['attrs', 'type', 'content'].includes(p))
})
}
// if (!opPathsExistInSchema(change.ops, editor.schema)) rebuildDiff() Type guard
function isApplicableOp (op: Operation, doc: ProsemirrorNode): boolean {
const from = (op as any).from
return from === undefined || (typeof from === 'number' && from <= doc.content.size)
} Try / catch
try {
recreateChangeContentSteps.call(recreator)
} catch (err) {
if (err instanceof Error && err.message.startsWith('No valid diff possible')) {
console.error('Diff replay diverged:', err.message)
fallbackToFullRedraw(recreator.targetDoc)
return
}
throw err
} Prevention
- Recompute diffs from the live document instead of replaying stale change records
- Version your editor schema and migrate stored change ops on upgrade
- Avoid concurrent edits during diff replay; lock or rebase first
When it happens
Trigger: Applying a stored diff/recreated change to a doc whose structure no longer matches (schema change, doc edited since the diff was captured); all ops fail and this.ops is empty so no further retry is possible.
Common situations: Collaborative documents modified concurrently while a diff was being replayed; editor schema upgraded so op paths (attrs/type) no longer exist; corrupted or hand-edited change records.
Related errors
- No valid step found.
- Unexpected line type: ${type}
- Please use the NodeViewWrapper component for your node view.
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/edcad11743d4ffd0.
Report an issue: GitHub.