d2lang/d2 · error

newSrc not found

Error message

newSrc not found

What it means

ReconnectEdge resolved the new source endpoint via `boardG.Root.HasChild`, but no object exists for the `srcKey` you passed. The edge's existing endpoints are found; the replacement source is not. Unlike the edge's other endpoints, ReconnectEdge does not create missing nodes for the new endpoint lookup.

Source

Thrown at d2oracle/edit.go:195

		if edge.Dst.AbsID() == *dstKey {
			dstKey = nil
		}
	}

	if srcKey == nil && dstKey == nil {
		return g, nil
	}

	var src *d2graph.Object
	var dst *d2graph.Object
	if srcKey != nil {
		srcmk, err := d2parser.ParseMapKey(*srcKey)
		if err != nil {
			return nil, err
		}
		src, ok = boardG.Root.HasChild(d2graph.Key(srcmk.Key))
		if !ok {
			return nil, errors.New("newSrc not found")
		}
	}
	if dstKey != nil {
		dstmk, err := d2parser.ParseMapKey(*dstKey)
		if err != nil {
			return nil, err
		}
		dst, ok = boardG.Root.HasChild(d2graph.Key(dstmk.Key))
		if !ok {
			return nil, errors.New("newDst not found")
		}
	}

	refs := edge.References
	if baseAST != g.AST {
		refs = GetWriteableEdgeRefs(edge, baseAST)
		if len(refs) == 0 || refs[0].ScopeAST != baseAST {
			// TODO null

View on GitHub (pinned to 0d69dca6f5)

Solutions

  1. Create the new source node first (e.g. via d2oracle.Create) so it exists in the graph before reconnecting.
  2. Verify srcKey resolves: parse it and check g.Root.HasChild(d2graph.Key(...)) before calling.
  3. Use the node's AbsID() as srcKey to guarantee exact matching.
  4. Ensure srcKey refers to a node in the same board passed via boardPath.

Example fix

// before
g, err = d2oracle.ReconnectEdge(g, nil, "x.(a -> b)", &newSrc, nil) // newSrc="q" doesn't exist
// after: ensure node exists first
if _, ok := g.Root.HasChild([]string{"q"}); !ok {
    g, _, err = d2oracle.Create(g, nil, "q", nil)
}
g, err = d2oracle.ReconnectEdge(g, nil, "x.(a -> b)", &newSrc, nil)
Defensive patterns

Strategy: validation

Validate before calling

srcmk, err := d2parser.ParseMapKey(newSrc)
if err != nil { return err }
if _, ok := g.Root.HasChild(d2graph.Key(srcmk.Key)); !ok {
    g, _, err = d2oracle.Create(g, nil, newSrc, nil)
    if err != nil { return err }
}

Type guard

func nodeExists(g *d2graph.Graph, id string) bool {
    mk, err := d2parser.ParseMapKey(id)
    if err != nil { return false }
    _, ok := g.Root.HasChild(d2graph.Key(mk.Key))
    return ok
}

Try / catch

g2, err := d2oracle.ReconnectEdge(g, nil, key, &newSrc, &newDst)
if err != nil && err.Error() == "newSrc not found" {
    g, _, err = d2oracle.Create(g, nil, newSrc, nil)
    if err != nil { return err }
    g2, err = d2oracle.ReconnectEdge(g, nil, key, &newSrc, &newDst)
}

Prevention

When it happens

Trigger: Calling d2oracle.ReconnectEdge with `srcKey` pointing to a node that does not exist in the target board: typo, node deleted earlier, node lives in a different board than boardPath, or an absolute ID that doesn't match the graph (e.g. wrong quotes/escapes).

Common situations: Batch scripts reconnecting edges after bulk node deletion; renaming a node then reconnecting with the old name; passing IDs from a different nested board; special characters in IDs not quoted.

Related errors


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