{"record":{"id":"2eae43b563a25869","repo":"toeverything/AFFiNE","slug":"cannot-move-a-node-to-its-descendant","errorCode":null,"errorMessage":"Cannot move a node to its descendant","messagePattern":"Cannot move a node to its descendant","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/frontend/core/src/modules/organize/stores/folder.ts","lineNumber":137,"sourceCode":"    const link = this.dbService.db.folders.get(linkId);\n    if (link === null || link.type === 'folder') {\n      throw new Error('Link not found');\n    }\n    this.dbService.db.folders.delete(linkId);\n  }\n\n  moveNode(nodeId: string, parentId: string | null, index: string) {\n    const node = this.dbService.db.folders.get(nodeId);\n    if (node === null) {\n      throw new Error('Node not found');\n    }\n\n    if (parentId) {\n      if (nodeId === parentId) {\n        throw new Error('Cannot move a node to itself');\n      }\n      if (this.isAncestor(parentId, nodeId)) {\n        throw new Error('Cannot move a node to its descendant');\n      }\n      const parent = this.dbService.db.folders.get(parentId);\n      if (parent === null || parent.type !== 'folder') {\n        throw new Error('Parent folder not found');\n      }\n    } else {\n      if (node.type !== 'folder') {\n        throw new Error('Root node can only have folders');\n      }\n    }\n    this.dbService.db.folders.update(nodeId, {\n      parentId,\n      index,\n    });\n  }\n}\n","sourceCodeStart":119,"sourceCodeEnd":154,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/packages/frontend/core/src/modules/organize/stores/folder.ts#L119-L154","documentation":"A cycle guard in moveNode: after ruling out self-parenting, isAncestor(parentId, nodeId) walks the ancestor chain and this fires when the target parent is a descendant of the node being moved. It prevents re-parenting a folder into its own subtree, which would create a cycle and orphan the branch.","triggerScenarios":"Thrown by moveNode when the target parentId is a descendant of the node being moved (isAncestor check), which would create a cycle in the folder tree.","commonSituations":"A user tries to move a folder into one of its own subfolders. Choose a destination outside the folder's own subtree.","solutions":["Choose a destination that is not inside the moved node.","Check descendants before moving."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"b4c8548c09da21b2898443559a5b846f0ccf5dd8","analyzedAt":"2026-08-18T21:16:52.546Z","contentChangedAt":"2026-08-18T21:16:52.546Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}