{"record":{"id":"f29a0b4ae657a3bb","repo":"donnemartin/interactive-coding-challenges","slug":"neighbor-not-found","errorCode":null,"errorMessage":"neighbor not found","messagePattern":"neighbor not found","errorType":"validation","errorClass":"KeyError","httpStatus":null,"severity":"error","filePath":"graphs_trees/graph/graph.py","lineNumber":37,"sourceCode":"\n    def __repr__(self):\n        return str(self.key)\n\n    def __lt__(self, other):\n        return self.key < other.key\n\n    def add_neighbor(self, neighbor, weight=0):\n        if neighbor is None or weight is None:\n            raise TypeError('neighbor or weight cannot be None')\n        neighbor.incoming_edges += 1\n        self.adj_weights[neighbor.key] = weight\n        self.adj_nodes[neighbor.key] = neighbor\n\n    def remove_neighbor(self, neighbor):\n        if neighbor is None:\n            raise TypeError('neighbor cannot be None')\n        if neighbor.key not in self.adj_nodes:\n            raise KeyError('neighbor not found')\n        neighbor.incoming_edges -= 1\n        del self.adj_weights[neighbor.key]\n        del self.adj_nodes[neighbor.key]\n\n\nclass Graph:\n\n    def __init__(self):\n        self.nodes = {}  # Key = key, val = Node\n\n    def add_node(self, key):\n        if key is None:\n            raise TypeError('key cannot be None')\n        if key not in self.nodes:\n            self.nodes[key] = Node(key)\n        return self.nodes[key]\n\n    def add_edge(self, source_key, dest_key, weight=0):","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/donnemartin/interactive-coding-challenges/blob/358f2cc60426d5c4c3d7d580910eec9a7b393fa9/graphs_trees/graph/graph.py#L19-L55","documentation":"Raised by Node.remove_neighbor when the neighbor's key is not present in this node's adjacency maps (adj_nodes/adj_weights). It prevents KeyError on the del statements and signals that no edge exists between the two nodes. Callers must ensure the edge was added before removing it.","triggerScenarios":"Calling remove_neighbor for a node never connected via add_neighbor/add_edge; removing the same edge twice; removing after the edge was already deleted.","commonSituations":"Double-remove bugs in cleanup code; attempting remove_edge on a graph where the edge was never added; race between checking and removing an edge.","solutions":["Guard with a membership check: if neighbor.key in node.adj_nodes before removing","Track added edges at the application level to prevent double removal","Catch KeyError as a signal the edge is already absent and treat as no-op"],"exampleFix":"# before\nnode.remove_neighbor(other)  # KeyError if no edge\n\n# after\nif other.key in node.adj_nodes:\n    node.remove_neighbor(other)","handlingStrategy":"type-guard","validationCode":"if neighbor.key in node.adj_nodes:\n    node.remove_neighbor(neighbor)","typeGuard":"def edge_exists(node, neighbor) -> bool:\n    return neighbor is not None and neighbor.key in node.adj_nodes","tryCatchPattern":"try:\n    node.remove_neighbor(neighbor)\nexcept KeyError:\n    pass  # edge already absent, idempotent","preventionTips":["Maintain a set of added edges to prevent double removal","Treat remove as idempotent by catching KeyError"],"tags":["graph","adjacency-list","keyerror","missing-edge"],"backgroundTag":"key-not-in-collection","analyzedSha":"358f2cc60426d5c4c3d7d580910eec9a7b393fa9","analyzedAt":"2026-08-28T10:16:54.480Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}