d2lang/d2 · error
edgeKey must be an edge
Error message
edgeKey must be an edge
What it means
ReconnectEdge in d2oracle takes an edgeKey string that must parse to a map key containing exactly the edge to reconnect. If the parsed map key has no edges (len(mk.Edges)==0), the input is not an edge key and this error is thrown before any edit.
Source
Thrown at d2oracle/edit.go:131
if len(boardPath) > 0 {
replaced := ReplaceBoardNode(g.AST, baseAST, boardPath)
if !replaced {
return nil, fmt.Errorf("board %v AST not found", boardPath)
}
}
return recompile(g)
}
func ReconnectEdge(g *d2graph.Graph, boardPath []string, edgeKey string, srcKey, dstKey *string) (_ *d2graph.Graph, err error) {
mk, err := d2parser.ParseMapKey(edgeKey)
if err != nil {
return nil, err
}
if len(mk.Edges) == 0 {
return nil, errors.New("edgeKey must be an edge")
}
if mk.EdgeIndex == nil {
return nil, errors.New("edgeKey must refer to an existing edge")
}
edgeTrimCommon(mk)
boardG := g
baseAST := g.AST
if len(boardPath) > 0 {
// When compiling a nested board, we can read from boardG but only write to baseBoardG
boardG = GetBoardGraph(g, boardPath)
if boardG == nil {
return nil, fmt.Errorf("board %v not found", boardPath)
}
// TODO beter nameView on GitHub (pinned to 0d69dca6f5)
Solutions
- Pass a key containing an edge arrow, e.g. "(a -> b)[0]" or "a -> b".
- Verify with d2parser.ParseMapKey yourself that mk.Edges is non-empty before calling.
- Make sure you selected the edge's key path from the AST (g.Edges[i].Key / absid), not a node id.
- If the key may contain multiple edges, include the edge index like (a -> b)[0].
Example fix
// before ReconnectEdge(g, "a", 0, "c", "d") // after ReconnectEdge(g, "a -> b", 0, "c", "d")
Defensive patterns
Strategy: validation
Validate before calling
mk, err := d2parser.ParseMapKey(edgeKey)
if err != nil || mk == nil || len(mk.Edges) == 0 {
return errors.New("edgeKey must contain an edge, e.g. \"a -> b\"")
} Type guard
func isEdgeKey(edgeKey string) bool {
mk, err := d2parser.ParseMapKey(edgeKey)
return err == nil && mk != nil && len(mk.Edges) > 0
} Try / catch
newKey, err := d2oracle.ReconnectEdge(g, edgeKey, edgeIndex, newSrc, newDst)
if err != nil && err.Error() == "edgeKey must be an edge" {
// surface "selection is not a connection" to the user
} Prevention
- Pass the key of an actual edge (contains ->), not a node id.
- Take edge keys from g.Edges rather than building strings by hand.
- Pre-validate user selections before calling ReconnectEdge.
When it happens
Trigger: Calling d2oracle.ReconnectEdge with an edgeKey that is a plain object key (no arrow), e.g. "a" or "a.b" instead of "a -> b"; an empty or whitespace key.
Common situations: Passing the wrong variable (object id instead of edge id) from application code; user-supplied keys from a UI where the selection wasn't actually an edge; keys like `a-b` that don't contain an arrow.
Related errors
- edgeKey must refer to an existing edge
- edge not found
- newSrc not found
- newDst not found
- can only set one edge at a time
AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31).
Data as JSON: /api/errors/072457595da09b59.
Report an issue: GitHub.