hcengineering/platform · error
No valid step found.
Error message
No valid step found.
What it means
addReplaceStep builds a ReplaceStep for a diff operation and applies it via tr.maybeStep; if the step can't be applied (the boolean helper returned false earlier) or the transaction step fails, it throws 'No valid step found.'. It indicates none of the constructed step variants could be validly applied at the computed position in the current document.
Source
Thrown at plugins/text-editor-resources/src/components/diff/recreate.ts:287
this.tr.addMark(from, to, nodeMark)
}
})
})
})
}
addReplaceStep (toDoc: Node, afterStepJSON: any): boolean {
const fromDoc = this.schema.nodeFromJSON(this.currentDoc)
const step = getReplaceStep(fromDoc, toDoc)
if (step == null) {
return false
} else if (this.tr.maybeStep(step).failed === null) {
this.currentDoc = afterStepJSON
return true // @change previously null
}
throw new Error('No valid step found.')
}
addReplaceTextSteps (op: any, afterStepJSON: any): void {
// We find the position number of the first character in the string
const op1 = { ...op, value: 'xx' }
const op2 = { ...op, value: 'yy' }
const afterOP1JSON = clone(this.currentDoc)
const afterOP2JSON = clone(this.currentDoc)
applyPatch(afterOP1JSON, [op1])
applyPatch(afterOP2JSON, [op2])
const op1Doc = this.schema.nodeFromJSON(afterOP1JSON)
const op2Doc = this.schema.nodeFromJSON(afterOP2JSON)
// get text diffs
const finalText = op.value
const currentText = getFromPath(this.currentDoc, op.path)
const textDiffs = diffWordsWithSpace(currentText, finalText)
View on GitHub (pinned to 63e28dc964)
Solutions
- Recompute positions against the current tr.doc (map through prior steps) before constructing the ReplaceStep
- Validate the op (value, path, node type) exists in the current schema before applying
- Log the op and tr.doc.slice positions to find why the step fails; maybeStep().failed contains the underlying reason
- Catch at recreateChangeContentSteps level and fall back to regenerating the diff from both docs
Example fix
// before
const step = new ReplaceStep(from, to, slice)
this.tr.maybeStep(step)
// after
const mapped = this.tr.mapping.map(from)
const mappedTo = this.tr.mapping.map(to)
if (mapped > this.tr.doc.content.size || mappedTo > this.tr.doc.content.size) {
throw new Error(`Op positions out of bounds after mapping: ${mapped}-${mappedTo}`)
}
this.tr.maybeStep(new ReplaceStep(mapped, mappedTo, slice)) Defensive patterns
Strategy: try-catch
Validate before calling
function positionInBounds (doc: ProsemirrorNode, from: number, to: number): boolean {
return from >= 0 && to >= from && to <= doc.content.size
}
// before building the step: if (!positionInBounds(tr.doc, from, to)) recomputePositions(tr) Type guard
function isReplaceStepApplicable (tr: Transaction, from: number, to: number): boolean {
return from >= 0 && to >= from && to <= tr.doc.content.size
} Try / catch
try {
this.addReplaceStep(op, afterStepJSON)
} catch (err) {
if (err instanceof Error && err.message === 'No valid step found.') {
console.error('ReplaceStep failed; op:', op)
remapAndRetry(tr, op)
return
}
throw err
} Prevention
- Map positions through tr.mapping after every prior step before computing new ones
- Validate node types/attrs against the current schema before constructing steps
- Keep diffs and documents in sync — regenerate rather than replay diverged change sets
When it happens
Trigger: An insert/replace op whose from/to positions don't fit the current doc (stale positions after earlier steps changed the doc); node type/attrs mismatch with the schema so the constructed step fails; empty/invalid op value producing an unusable step.
Common situations: Replaying diffs against a document that changed since capture; schema evolution invalidating stored node types; position mapping bugs after chained operations.
Related errors
- No valid diff possible applying ${op.path} ${JSON.stringify(
- 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/5c99f42eace93d6a.
Report an issue: GitHub.