{"record":{"id":"e5fcfbdb56f45249","repo":"trekhleb/javascript-algorithms","slug":"edge-has-already-been-added-before","errorCode":null,"errorMessage":"Edge has already been added before","messagePattern":"Edge has already been added before","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/data-structures/graph/Graph.js","lineNumber":80,"sourceCode":"    // Try to find and end start vertices.\n    let startVertex = this.getVertexByKey(edge.startVertex.getKey());\n    let endVertex = this.getVertexByKey(edge.endVertex.getKey());\n\n    // Insert start vertex if it wasn't inserted.\n    if (!startVertex) {\n      this.addVertex(edge.startVertex);\n      startVertex = this.getVertexByKey(edge.startVertex.getKey());\n    }\n\n    // Insert end vertex if it wasn't inserted.\n    if (!endVertex) {\n      this.addVertex(edge.endVertex);\n      endVertex = this.getVertexByKey(edge.endVertex.getKey());\n    }\n\n    // Check if edge has been already added.\n    if (this.edges[edge.getKey()]) {\n      throw new Error('Edge has already been added before');\n    } else {\n      this.edges[edge.getKey()] = edge;\n    }\n\n    // Add edge to the vertices.\n    if (this.isDirected) {\n      // If graph IS directed then add the edge only to start vertex.\n      startVertex.addEdge(edge);\n    } else {\n      // If graph ISN'T directed then add the edge to both vertices.\n      startVertex.addEdge(edge);\n      endVertex.addEdge(edge);\n    }\n\n    return this;\n  }\n\n  /**","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/graph/Graph.js#L62-L98","documentation":"Graph.addEdge() indexes edges by edge.getKey(), which GraphEdge computes as `${startVertex.getKey()}_${endVertex.getKey()}` (or a custom key passed to its constructor). After auto-inserting missing endpoint vertices, the guard at Graph.js:79-83 refuses a second edge with the same key, so the graph holds at most one edge per ordered vertex pair. The check is direction-aware even in undirected graphs: keys A_B and B_A are different.","triggerScenarios":"graph.addEdge(edge) called twice with the same GraphEdge object; two different GraphEdge instances joining the same pair in the same direction; an input edge list containing duplicate rows; two edges sharing an explicit custom key passed as new GraphEdge(start, end, weight, key).","commonSituations":"Importing adjacency lists or CSV edge data with duplicate pairs; retry/re-sync logic that re-adds edges after a partial failure; attempting to model parallel edges (a multigraph) - this structure cannot represent them, so the second insert throws.","solutions":["Check before adding: if (!graph.findEdge(start, end)) graph.addEdge(new GraphEdge(start, end)); - findEdge() matches either orientation, which matters for undirected graphs.","Deduplicate the input edge list first on a canonical `${u}_${v}` key before inserting anything.","Model multiplicity with weight instead of parallel edges: find the existing edge via findEdge() and increase its weight.","If edges carry a custom key, make sure keys are unique per edge."],"exampleFix":"// before\ngraph.addEdge(new GraphEdge(a, b));\ngraph.addEdge(new GraphEdge(a, b)); // Error: Edge has already been added before\n\n// after\nconst edge = new GraphEdge(a, b);\nif (!graph.findEdge(a, b)) {\n  graph.addEdge(edge);\n}","handlingStrategy":"validation","validationCode":"// findEdge() returns the stored edge for either orientation (undirected-safe)\nif (!graph.findEdge(startVertex, endVertex)) {\n  graph.addEdge(new GraphEdge(startVertex, endVertex));\n}","typeGuard":null,"tryCatchPattern":"try {\n  graph.addEdge(edge);\n} catch (error) {\n  if (error.message === 'Edge has already been added before') {\n    const existing = graph.findEdge(edge.startVertex, edge.endVertex);\n    existing.weight += edge.weight; // fold duplicates into weight, if meaningful\n  } else {\n    throw error;\n  }\n}","preventionTips":["Deduplicate edge pairs at ingest time on a canonical `${min}_${max}` (undirected) or `${u}_${v}` (directed) key.","Check graph.findEdge() before every addEdge() when input is not guaranteed unique.","Represent multiplicity as edge weight, not repeated edges - this structure is not a multigraph.","Keep custom edge keys unique; they bypass the auto-generated key."],"tags":["graph","duplicate-edge","unique-key","multigraph","add-edge"],"backgroundTag":"duplicate-key-insertion","analyzedSha":"85293e3e2b88f4d2ce330d956b139cf628aa1e82","analyzedAt":"2026-08-24T05:59:10.417Z","schemaVersion":2},"datasetVersion":"2026-08-24T07:17:09.176Z"}