{"record":{"id":"ab993215f4aed610","repo":"ianstormtaylor/slate","slug":"cannot-get-the-previous-path-of-a-root-path-pat","errorCode":null,"errorMessage":"Cannot get the previous path of a root path [${path}], because it has no previous index.","messagePattern":"Cannot get the previous path of a root path \\[(.+?)\\], because it has no previous index\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/slate/src/interfaces/path.ts","lineNumber":366,"sourceCode":"      case 'split_node':\n      case 'move_node':\n        return true\n      default:\n        return false\n    }\n  },\n\n  parent(path: Path): Path {\n    if (path.length === 0) {\n      throw new Error(`Cannot get the parent path of the root path [${path}].`)\n    }\n\n    return path.slice(0, -1)\n  },\n\n  previous(path: Path): Path {\n    if (path.length === 0) {\n      throw new Error(\n        `Cannot get the previous path of a root path [${path}], because it has no previous index.`\n      )\n    }\n\n    const last = path[path.length - 1]\n\n    if (last <= 0) {\n      throw new Error(\n        `Cannot get the previous path of a first child path [${path}] because it would result in a negative index.`\n      )\n    }\n\n    return path.slice(0, -1).concat(last - 1)\n  },\n\n  relative(path: Path, ancestor: Path): Path {\n    if (!Path.isAncestor(ancestor, path) && !Path.equals(path, ancestor)) {\n      throw new Error(","sourceCodeStart":348,"sourceCodeEnd":384,"githubUrl":"https://github.com/ianstormtaylor/slate/blob/72a37c701e5da4bb13a305d416d9c070d19d3a45/packages/slate/src/interfaces/path.ts#L348-L384","documentation":"Path.previous() returns the preceding sibling path by decrementing the last index. The root path [] has no last index, so there is no previous sibling and Slate throws. Note this checks only the root; a path like [0] returns [-1], which is invalid but does not throw here — bounds checks are the caller's job.","triggerScenarios":"Calling Path.previous([]) directly; reverse iteration walking siblings upward without a root guard; calling Path.previous(Path.parent(p)) when p had length 1, yielding the root path first.","commonSituations":"Iterating siblings backwards (for (let q = last; ; q = Path.previous(q))) without stopping at the first sibling or the root; loop conditions that assume previous() returns null/undefined at the boundary instead of throwing; porting traversal code that used next() and forgetting the asymmetry.","solutions":["Guard before decrementing: if (path.length === 0) stop — and also stop when the last index reaches 0 to avoid producing [-1].","Bound reverse loops by the first sibling: while (lastIndex >= 0) { visit(...path, lastIndex); lastIndex-- } or compare against Path.parent's children length.","Prefer built-in traversals (Node.nodes with reverse: true) which handle sibling boundaries correctly.","Add explicit root checks in any code that chains Path.parent then Path.previous."],"exampleFix":"// before\nlet p = somePath\nwhile (true) { visit(p); p = Path.previous(p) } // throws on []\n\n// after\nlet p = somePath\nwhile (p.length > 0 && p[p.length - 1] >= 0 && Editor.hasPath(editor, p)) {\n  visit(p)\n  p = Path.previous(p)\n}","handlingStrategy":"validation","validationCode":"if (path.length === 0 || path[path.length - 1] === 0) { /* no previous sibling */ }","typeGuard":"const hasPrevSibling = (p: Path): boolean => p.length > 0 && p[p.length - 1] > 0","tryCatchPattern":null,"preventionTips":["Stop reverse sibling loops at the first sibling (last index 0), not just at the root.","Prefer Node.nodes with reverse: true over manual previous() walking."],"tags":["slate","path","iteration","bounds"],"backgroundTag":"slate-invalid-path","analyzedSha":"72a37c701e5da4bb13a305d416d9c070d19d3a45","analyzedAt":"2026-08-27T23:04:51.145Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}