{"record":{"id":"dd4bc43de7a1c1d7","repo":"ianstormtaylor/slate","slug":"cannot-resolve-a-slate-point-from-dom-point-dom","errorCode":null,"errorMessage":"Cannot resolve a Slate point from DOM point: ${domPoint}","messagePattern":"Cannot resolve a Slate point from DOM point: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/slate-dom/src/plugin/dom-editor.ts","lineNumber":915,"sourceCode":"            return null as T extends true ? Point | null : Point\n          }\n          throw e\n        }\n        let { path, offset } = Editor.start(editor, nodePath)\n\n        if (!node.querySelector('[data-slate-leaf]')) {\n          offset = nearestOffset\n        }\n\n        return { path, offset } as T extends true ? Point | null : Point\n      }\n    }\n\n    if (!textNode) {\n      if (suppressThrow) {\n        return null as T extends true ? Point | null : Point\n      }\n      throw new Error(\n        `Cannot resolve a Slate point from DOM point: ${domPoint}`\n      )\n    }\n\n    // COMPAT: If someone is clicking from one Slate editor into another,\n    // the select event fires twice, once for the old editor's `element`\n    // first, and then afterwards for the correct `element`. (2017/03/03)\n    let slateNode\n    try {\n      slateNode = DOMEditor.toSlateNode(editor, textNode!)\n    } catch (e) {\n      if (suppressThrow) {\n        return null as T extends true ? Point | null : Point\n      }\n      throw e\n    }\n    let path\n    try {","sourceCodeStart":897,"sourceCodeEnd":933,"githubUrl":"https://github.com/ianstormtaylor/slate/blob/72a37c701e5da4bb13a305d416d9c070d19d3a45/packages/slate-dom/src/plugin/dom-editor.ts#L897-L933","documentation":"Thrown by DOMEditor.toSlatePoint when the DOM point cannot be mapped to a Slate text node — typically when the DOM node under the point is not a Slate text leaf (or the closest slate leaf lookup fails) and suppressThrow is not enabled.","triggerScenarios":"Calling toSlatePoint on a DOM point inside a void element's spacer, an element boundary between nodes, or DOM produced by another editor; also cross-editor clicks where the old editor resolves a point targeting the new editor's DOM.","commonSituations":"Selection/drop handlers that read window.getSelection() when it briefly sits on non-Slate DOM (void spacers, padding elements), or programmatic selections created with Range APIs that don't align to Slate leaves.","solutions":["Pass suppressThrow: true and handle the null return","Use DOMEditor.toSlateRange with suppressThrow for whole-selection reads","Clamp DOM points into the editable before converting","For void nodes, resolve selection to the void node's edge instead of its inner DOM"],"exampleFix":"// before\nconst p = DOMEditor.toSlatePoint(editor, domPoint, { suppressThrow: false })\n// after\nconst p = DOMEditor.toSlatePoint(editor, domPoint, { suppressThrow: true })\nif (p == null) return","handlingStrategy":"fallback","validationCode":"const p = DOMEditor.toSlatePoint(editor, domPoint, { suppressThrow: true })\nif (p == null) { /* handle non-mappable point (void, boundary) */ }","typeGuard":"null","tryCatchPattern":"try { DOMEditor.toSlatePoint(editor, domPoint, { suppressThrow: false }) } catch (e) { if (/Cannot resolve a Slate point/.test(e.message)) return null; else throw e }","preventionTips":["Prefer suppressThrow: true when reading arbitrary DOM points","Clamp selections to the editable before conversion","Handle void-node selections at the node edge, not inner DOM"],"tags":["slate","selection","dom-point","void-node"],"backgroundTag":"dom-point-not-mappable","analyzedSha":"72a37c701e5da4bb13a305d416d9c070d19d3a45","analyzedAt":"2026-08-27T23:04:51.145Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}