{"record":{"id":"4c92c5335d483b08","repo":"d2lang/d2","slug":"edgekey-must-refer-to-an-existing-edge","errorCode":null,"errorMessage":"edgeKey must refer to an existing edge","messagePattern":"edgeKey must refer to an existing edge","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"d2oracle/edit.go","lineNumber":135,"sourceCode":"\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\n\t\tbaseAST = boardG.BaseAST\n\t\tif baseAST == nil {\n\t\t\treturn nil, fmt.Errorf(\"board %v cannot be modified through this file\", boardPath)\n\t\t}","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/d2lang/d2/blob/0d69dca6f532ceaeacd615d35d1eaa41a238ffdb/d2oracle/edit.go#L117-L153","documentation":"ReconnectEdge requires the edgeKey to include an explicit edge index (e.g. `(a -> b)[0]`) so it knows which edge to modify when multiple edges exist on the key. If mk.EdgeIndex is nil after parsing, the key doesn't disambiguate an existing edge and this error is thrown.","triggerScenarios":"Calling ReconnectEdge with an edge key like \"a -> b\" that omits the (key)[index] form, or with an index/key combination that parsed to nil EdgeIndex — commonly when the key has multiple edge representations.","commonSituations":"Using g.Edges[i].Key straight from the graph when it lacks an index for multi-edge keys; hand-writing edge keys in tools and omitting the [0] index; multiple connections between the same endpoints requiring index disambiguation.","solutions":["Use the indexed key form: \"(a -> b)[0]\" instead of \"a -> b\".","Take the exact key from g.Edges[i].AST / the board AST rather than constructing it manually.","If multiple edges share the key, identify the correct index and pass it via edgeIndex while the key includes the (…)[] form.","Use d2oracle to inspect g.Edges and reuse its key string verbatim."],"exampleFix":"// before\nReconnectEdge(g, \"a -> b\", 0, \"c\", \"d\")\n// after\nReconnectEdge(g, \"(a -> b)[0]\", 0, \"c\", \"d\")","handlingStrategy":"validation","validationCode":"mk, _ := d2parser.ParseMapKey(edgeKey)\nif mk != nil && mk.EdgeIndex == nil {\n  edgeKey = fmt.Sprintf(\"(%s)[0]\", edgeKey)\n}","typeGuard":"func edgeKeyHasIndex(edgeKey string) bool {\n  mk, err := d2parser.ParseMapKey(edgeKey)\n  return err == nil && mk != nil && mk.EdgeIndex != nil\n}","tryCatchPattern":"newKey, err := d2oracle.ReconnectEdge(g, edgeKey, edgeIndex, newSrc, newDst)\nif err != nil && err.Error() == \"edgeKey must refer to an existing edge\" {\n  // add the (key)[index] form and retry\n}","preventionTips":["Use the (key)[index] form for edge keys passed to d2oracle edits.","Copy keys verbatim from the graph AST instead of reconstructing them.","Include the edge index whenever multiple edges may share a key."],"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"}