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 name

View on GitHub (pinned to 0d69dca6f5)

Solutions

  1. Pass a key containing an edge arrow, e.g. "(a -> b)[0]" or "a -> b".
  2. Verify with d2parser.ParseMapKey yourself that mk.Edges is non-empty before calling.
  3. Make sure you selected the edge's key path from the AST (g.Edges[i].Key / absid), not a node id.
  4. 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

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


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