d2lang/d2 · error

to parent not found

Error message

to parent not found

What it means

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'.

Source

Thrown at d2oracle/edit.go:2908

			return nil, nil
		}
		beforeID := e.AbsID()
		tmp := *e
		e2 := &tmp
		e2.SrcArrow = mk2.Edges[0].SrcArrow == "<"
		e2.DstArrow = mk2.Edges[0].DstArrow == ">"
		deltas[beforeID] = e2.AbsID()
		return deltas, nil
	}

	beforeObjID := obj.ID

	toParent := g.Root
	if len(ak2) > 1 {
		var ok bool
		toParent, ok = g.Root.HasChild(ak2[:len(ak2)-1])
		if !ok {
			return nil, errors.New("to parent not found")
		}
	}
	id := ak2[len(ak2)-1]

	tmpRenames := func() func() {
		if isCrossScope && !includeDescendants {
			for _, ch := range obj.ChildrenArray {
				ch.Parent = obj.Parent
			}
		}

		prevParent := obj.Parent
		obj.Parent = toParent
		obj.ID = id

		for k, v := range conflictNewIDs {
			k.ID = v
		}

View on GitHub (pinned to 0d69dca6f5)

Solutions

  1. Create the destination parent containers first (e.g. via oracle.Set for the full path) before moving the object
  2. Use d2graph g.Root.HasChild(parentPath) in the caller to verify the parent exists before calling MoveIDDeltas
  3. Check for typos or board-scope mistakes in the destination ID path

Example fix

// before
renamed, err := oracle.MoveIDDeltas(ctx, g, "x", "a.b.x", nil) // 'a.b' may not exist
// after
if _, ok := g.Root.HasChild([]string{"a", "b"}); ok {
    renamed, err = oracle.MoveIDDeltas(ctx, g, "x", "a.b.x", nil)
} else {
    // create containers a and b first
}
Defensive patterns

Strategy: validation

Validate before calling

if len(ak2) > 1 {
    if _, ok := g.Root.HasChild(ak2[:len(ak2)-1]); !ok {
        return errors.New("destination parent does not exist")
    }
}

Type guard

func parentExists(g *d2graph.Graph, path []string) bool {
    if len(path) <= 1 { return true }
    _, ok := g.Root.HasChild(path[:len(path)-1])
    return ok
}

Try / catch

_, err := oracle.MoveIDDeltas(ctx, g, oldID, newName, nil)
if err != nil && strings.Contains(err.Error(), "to parent not found") {
    // create parent containers, then retry once
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31). Data as JSON: /api/errors/20520bf6cf3cb8d7. Report an issue: GitHub.