{"record":{"id":"072457595da09b59","repo":"d2lang/d2","slug":"edgekey-must-be-an-edge","errorCode":null,"errorMessage":"edgeKey must be an edge","messagePattern":"edgeKey must be an edge","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"d2oracle/edit.go","lineNumber":131,"sourceCode":"\n\tif len(boardPath) > 0 {\n\t\treplaced := ReplaceBoardNode(g.AST, baseAST, boardPath)\n\t\tif !replaced {\n\t\t\treturn nil, fmt.Errorf(\"board %v AST not found\", boardPath)\n\t\t}\n\t}\n\n\treturn recompile(g)\n}\n\nfunc ReconnectEdge(g *d2graph.Graph, boardPath []string, edgeKey string, srcKey, dstKey *string) (_ *d2graph.Graph, err error) {\n\tmk, err := d2parser.ParseMapKey(edgeKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(mk.Edges) == 0 {\n\t\treturn nil, errors.New(\"edgeKey must be an edge\")\n\t}\n\n\tif mk.EdgeIndex == nil {\n\t\treturn nil, errors.New(\"edgeKey must refer to an existing edge\")\n\t}\n\n\tedgeTrimCommon(mk)\n\n\tboardG := g\n\tbaseAST := g.AST\n\n\tif len(boardPath) > 0 {\n\t\t// When compiling a nested board, we can read from boardG but only write to baseBoardG\n\t\tboardG = GetBoardGraph(g, boardPath)\n\t\tif boardG == nil {\n\t\t\treturn nil, fmt.Errorf(\"board %v not found\", boardPath)\n\t\t}\n\t\t// TODO beter name","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/d2lang/d2/blob/0d69dca6f532ceaeacd615d35d1eaa41a238ffdb/d2oracle/edit.go#L113-L149","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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]."],"exampleFix":"// before\nReconnectEdge(g, \"a\", 0, \"c\", \"d\")\n// after\nReconnectEdge(g, \"a -> b\", 0, \"c\", \"d\")","handlingStrategy":"validation","validationCode":"mk, err := d2parser.ParseMapKey(edgeKey)\nif err != nil || mk == nil || len(mk.Edges) == 0 {\n  return errors.New(\"edgeKey must contain an edge, e.g. \\\"a -> b\\\"\")\n}","typeGuard":"func isEdgeKey(edgeKey string) bool {\n  mk, err := d2parser.ParseMapKey(edgeKey)\n  return err == nil && mk != nil && len(mk.Edges) > 0\n}","tryCatchPattern":"newKey, err := d2oracle.ReconnectEdge(g, edgeKey, edgeIndex, newSrc, newDst)\nif err != nil && err.Error() == \"edgeKey must be an edge\" {\n  // surface \"selection is not a connection\" to the user\n}","preventionTips":["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."],"tags":["d2","d2oracle","edge","input-validation"],"backgroundTag":"invalid-edge-key","analyzedSha":"0d69dca6f532ceaeacd615d35d1eaa41a238ffdb","analyzedAt":"2026-08-31T12:19:21.182Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}