{"record":{"id":"8eded42d17b00d4e","repo":"ianstormtaylor/slate","slug":"slate-hyperscript-ranges-must-have-both-anchor","errorCode":null,"errorMessage":"Slate hyperscript ranges must have both `<anchor />` and `<focus />` defined if one is defined, but you only defined `<anchor />`. For collapsed selections, use `<cursor />` instead.","messagePattern":"Slate hyperscript ranges must have both `<anchor />` and `<focus />` defined if one is defined, but you only defined `<anchor />`\\. For collapsed selections, use `<cursor />` instead\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/slate-hyperscript/src/creators.ts","lineNumber":277,"sourceCode":"        }\n      }\n\n      for (const { ref = selection, offset } of getFoci(node)) {\n        if (offset != null) {\n          ref.focus = { path, offset }\n        }\n      }\n\n      for (const { ref, offset } of getPoints(node)) {\n        if (ref) {\n          ref.offset = offset\n          ref.path = path\n        }\n      }\n    }\n\n    if (selection.anchor && !selection.focus) {\n      throw new Error(\n        `Slate hyperscript ranges must have both \\`<anchor />\\` and \\`<focus />\\` defined if one is defined, but you only defined \\`<anchor />\\`. For collapsed selections, use \\`<cursor />\\` instead.`\n      )\n    }\n\n    if (!selection.anchor && selection.focus) {\n      throw new Error(\n        `Slate hyperscript ranges must have both \\`<anchor />\\` and \\`<focus />\\` defined if one is defined, but you only defined \\`<focus />\\`. For collapsed selections, use \\`<cursor />\\` instead.`\n      )\n    }\n\n    if (selectionChild != null) {\n      editor.selection = selectionChild\n    } else if (Range.isRange(selection)) {\n      editor.selection = selection\n    }\n\n    return editor\n  }","sourceCodeStart":259,"sourceCodeEnd":295,"githubUrl":"https://github.com/ianstormtaylor/slate/blob/72a37c701e5da4bb13a305d416d9c070d19d3a45/packages/slate-hyperscript/src/creators.ts#L259-L295","documentation":"Thrown by hyperscript's createEditor when an <anchor /> token was placed in the value but no matching <focus /> token exists. Slate ranges need both ends; hyperscript enforces the pair (or the collapsed <cursor /> alternative).","triggerScenarios":"Writing jsx(<editor><paragraph><anchor path={[0,0]} offset={0}/>text</paragraph></editor>) without a focus token.","commonSituations":"Authoring test editors where only the anchor was added, or where the focus token was accidentally removed during refactor.","solutions":["Add the matching <focus path={...} offset={...} /> token","Replace the lone <anchor /> with <cursor /> for a collapsed selection"],"exampleFix":"// before\n<editor>\n  <paragraph><anchor path={[0,0]} offset={0} />hello</paragraph>\n</editor>\n// after\n<editor>\n  <paragraph><anchor path={[0,0]} offset={0} />hel<focus path={[0,0]} offset={3} />lo</paragraph>\n</editor>","handlingStrategy":"validation","validationCode":"// fixture invariant: count anchor and focus tokens\nconst anchors = countTokens(value, AnchorToken)\nconst focuses = countTokens(value, FocusToken)\nif (anchors !== focuses) throw new Error('anchor/focus tokens must be paired')","typeGuard":"const isPairedSelectionTokens = (a: number, f: number): boolean => a === f","tryCatchPattern":"null","preventionTips":["Always emit <anchor/> and <focus/> as a pair","Use <cursor/> for collapsed selections","Review selection tags after refactoring fixtures"],"tags":["slate","hyperscript","selection","anchor"],"backgroundTag":"hyperscript-selection-missing-focus","analyzedSha":"72a37c701e5da4bb13a305d416d9c070d19d3a45","analyzedAt":"2026-08-27T23:04:51.145Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}