{"record":{"id":"5c99f42eace93d6a","repo":"hcengineering/platform","slug":"no-valid-step-found","errorCode":null,"errorMessage":"No valid step found.","messagePattern":"No valid step found\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/text-editor-resources/src/components/diff/recreate.ts","lineNumber":287,"sourceCode":"            this.tr.addMark(from, to, nodeMark)\n          }\n        })\n      })\n    })\n  }\n\n  addReplaceStep (toDoc: Node, afterStepJSON: any): boolean {\n    const fromDoc = this.schema.nodeFromJSON(this.currentDoc)\n    const step = getReplaceStep(fromDoc, toDoc)\n\n    if (step == null) {\n      return false\n    } else if (this.tr.maybeStep(step).failed === null) {\n      this.currentDoc = afterStepJSON\n      return true // @change previously null\n    }\n\n    throw new Error('No valid step found.')\n  }\n\n  addReplaceTextSteps (op: any, afterStepJSON: any): void {\n    // We find the position number of the first character in the string\n    const op1 = { ...op, value: 'xx' }\n    const op2 = { ...op, value: 'yy' }\n    const afterOP1JSON = clone(this.currentDoc)\n    const afterOP2JSON = clone(this.currentDoc)\n    applyPatch(afterOP1JSON, [op1])\n    applyPatch(afterOP2JSON, [op2])\n    const op1Doc = this.schema.nodeFromJSON(afterOP1JSON)\n    const op2Doc = this.schema.nodeFromJSON(afterOP2JSON)\n\n    // get text diffs\n    const finalText = op.value\n    const currentText = getFromPath(this.currentDoc, op.path)\n    const textDiffs = diffWordsWithSpace(currentText, finalText)\n","sourceCodeStart":269,"sourceCodeEnd":305,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/plugins/text-editor-resources/src/components/diff/recreate.ts#L269-L305","documentation":"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.","triggerScenarios":"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.","commonSituations":"Replaying diffs against a document that changed since capture; schema evolution invalidating stored node types; position mapping bugs after chained operations.","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"],"exampleFix":"// before\nconst step = new ReplaceStep(from, to, slice)\nthis.tr.maybeStep(step)\n// after\nconst mapped = this.tr.mapping.map(from)\nconst mappedTo = this.tr.mapping.map(to)\nif (mapped > this.tr.doc.content.size || mappedTo > this.tr.doc.content.size) {\n  throw new Error(`Op positions out of bounds after mapping: ${mapped}-${mappedTo}`)\n}\nthis.tr.maybeStep(new ReplaceStep(mapped, mappedTo, slice))","handlingStrategy":"try-catch","validationCode":"function positionInBounds (doc: ProsemirrorNode, from: number, to: number): boolean {\n  return from >= 0 && to >= from && to <= doc.content.size\n}\n// before building the step: if (!positionInBounds(tr.doc, from, to)) recomputePositions(tr)","typeGuard":"function isReplaceStepApplicable (tr: Transaction, from: number, to: number): boolean {\n  return from >= 0 && to >= from && to <= tr.doc.content.size\n}","tryCatchPattern":"try {\n  this.addReplaceStep(op, afterStepJSON)\n} catch (err) {\n  if (err instanceof Error && err.message === 'No valid step found.') {\n    console.error('ReplaceStep failed; op:', op)\n    remapAndRetry(tr, op)\n    return\n  }\n  throw err\n}","preventionTips":["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"],"tags":["prosemirror","diff","step-application"],"backgroundTag":"diff-application-failed","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}