{"record":{"id":"20520bf6cf3cb8d7","repo":"d2lang/d2","slug":"to-parent-not-found","errorCode":null,"errorMessage":"to parent not found","messagePattern":"to parent not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"d2oracle/edit.go","lineNumber":2908,"sourceCode":"\t\t\treturn nil, nil\n\t\t}\n\t\tbeforeID := e.AbsID()\n\t\ttmp := *e\n\t\te2 := &tmp\n\t\te2.SrcArrow = mk2.Edges[0].SrcArrow == \"<\"\n\t\te2.DstArrow = mk2.Edges[0].DstArrow == \">\"\n\t\tdeltas[beforeID] = e2.AbsID()\n\t\treturn deltas, nil\n\t}\n\n\tbeforeObjID := obj.ID\n\n\ttoParent := g.Root\n\tif len(ak2) > 1 {\n\t\tvar ok bool\n\t\ttoParent, ok = g.Root.HasChild(ak2[:len(ak2)-1])\n\t\tif !ok {\n\t\t\treturn nil, errors.New(\"to parent not found\")\n\t\t}\n\t}\n\tid := ak2[len(ak2)-1]\n\n\ttmpRenames := func() func() {\n\t\tif isCrossScope && !includeDescendants {\n\t\t\tfor _, ch := range obj.ChildrenArray {\n\t\t\t\tch.Parent = obj.Parent\n\t\t\t}\n\t\t}\n\n\t\tprevParent := obj.Parent\n\t\tobj.Parent = toParent\n\t\tobj.ID = id\n\n\t\tfor k, v := range conflictNewIDs {\n\t\t\tk.ID = v\n\t\t}","sourceCodeStart":2890,"sourceCodeEnd":2926,"githubUrl":"https://github.com/d2lang/d2/blob/0d69dca6f532ceaeacd615d35d1eaa41a238ffdb/d2oracle/edit.go#L2890-L2926","documentation":"During a move/rename, MoveIDDeltas computes the parent of the destination ID from the parsed new key ak2. If the destination has multiple path segments, it looks up the ancestors under the root with HasChild; when those intermediate containers do not exist in the graph, the move cannot proceed and it returns 'to parent not found'.","triggerScenarios":"Calling MoveIDDeltas with a newName whose parent path (ak2[:len(ak2)-1], when len(ak2)>1) does not resolve to an existing container in the graph, e.g. moving 'x' to 'a.b.c' where 'a.b' does not exist.","commonSituations":"Renaming an object into a namespace that was renamed or deleted elsewhere; typos in the destination path; moving objects between boards where the target scope was never created; stale references in tooling built on the oracle API.","solutions":["Create the destination parent containers first (e.g. via oracle.Set for the full path) before moving the object","Use d2graph g.Root.HasChild(parentPath) in the caller to verify the parent exists before calling MoveIDDeltas","Check for typos or board-scope mistakes in the destination ID path"],"exampleFix":"// before\nrenamed, err := oracle.MoveIDDeltas(ctx, g, \"x\", \"a.b.x\", nil) // 'a.b' may not exist\n// after\nif _, ok := g.Root.HasChild([]string{\"a\", \"b\"}); ok {\n    renamed, err = oracle.MoveIDDeltas(ctx, g, \"x\", \"a.b.x\", nil)\n} else {\n    // create containers a and b first\n}","handlingStrategy":"validation","validationCode":"if len(ak2) > 1 {\n    if _, ok := g.Root.HasChild(ak2[:len(ak2)-1]); !ok {\n        return errors.New(\"destination parent does not exist\")\n    }\n}","typeGuard":"func parentExists(g *d2graph.Graph, path []string) bool {\n    if len(path) <= 1 { return true }\n    _, ok := g.Root.HasChild(path[:len(path)-1])\n    return ok\n}","tryCatchPattern":"_, err := oracle.MoveIDDeltas(ctx, g, oldID, newName, nil)\nif err != nil && strings.Contains(err.Error(), \"to parent not found\") {\n    // create parent containers, then retry once\n}","preventionTips":["Always verify destination parent path exists with HasChild before moving","Create namespaces with oracle.Set before moving objects into them","Watch for board-scope paths differing from root scope"],"tags":["d2","move","graph-structure"],"backgroundTag":"target-parent-not-found","analyzedSha":"0d69dca6f532ceaeacd615d35d1eaa41a238ffdb","analyzedAt":"2026-08-31T12:19:21.182Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}