d2lang/d2 · error
newDst not found
Error message
newDst not found
What it means
Same failure mode as newSrc but for the destination: ReconnectEdge parsed `dstKey` and could not find a matching object under the board's root. The rewire is aborted so the graph is never left with a dangling destination.
Source
Thrown at d2oracle/edit.go:205
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
return nil, OutsideScopeError{}
}
}
ref := refs[0]
// for loops where only one end is changing, node is always ensured
if edge.Src != edge.Dst && (srcKey == nil || dstKey == nil) {
var refEdges []*d2ast.Edge
for _, ref := range refs {
refEdges = append(refEdges, ref.Edge)View on GitHub (pinned to 0d69dca6f5)
Solutions
- Create the destination node first via d2oracle.Create, then call ReconnectEdge.
- Pre-validate dstKey with g.Root.HasChild on the parsed key.
- Pass the destination node's AbsID() as dstKey.
- Make sure boardPath matches the board where the dst node actually lives.
Example fix
// before
g, err = d2oracle.ReconnectEdge(g, []string{"layers.x"}, "a -> b", nil, &newDst) // newDst missing in board
// after
if _, ok := boardG.Root.HasChild([]string{"c"}); !ok {
g, _, err = d2oracle.Create(g, nil, "c", nil)
}
g, err = d2oracle.ReconnectEdge(g, []string{"layers.x"}, "a -> b", nil, &newDst) Defensive patterns
Strategy: validation
Validate before calling
dstmk, err := d2parser.ParseMapKey(newDst)
if err != nil { return err }
if _, ok := g.Root.HasChild(d2graph.Key(dstmk.Key)); !ok {
g, _, err = d2oracle.Create(g, nil, newDst, 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, boardPath, key, nil, &newDst)
if err != nil && err.Error() == "newDst not found" {
g, _, err = d2oracle.Create(g, nil, newDst, nil)
if err != nil { return err }
g2, err = d2oracle.ReconnectEdge(g, boardPath, key, nil, &newDst)
} Prevention
- Ensure the destination node exists in the same board passed via boardPath
- Use AbsID() for endpoint keys
- Auto-create missing endpoints as a standard pre-step in rewire tooling
- Validate dstKey right after user input, before graph mutation
When it happens
Trigger: Calling d2oracle.ReconnectEdge with `dstKey` for a non-existent node: typo, dst node deleted, dst in another board than boardPath, or unquoted special characters in the ID path.
Common situations: Reconnecting an edge to a target the user just typed that was never created; tooling that assumes ReconnectEdge auto-creates endpoints (it does not for the dst lookup); nested board sketches where the target exists only on the root board.
Related errors
- newSrc not found
- edge not found
- edgeKey must be an edge
- edgeKey must refer to an existing edge
- can only set one edge at a time
AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31).
Data as JSON: /api/errors/359249165cc4ef1d.
Report an issue: GitHub.