{"record":{"id":"9df9516ce4264359","repo":"donnemartin/interactive-coding-challenges","slug":"neighbor-cannot-be-none","errorCode":null,"errorMessage":"neighbor cannot be None","messagePattern":"neighbor cannot be None","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"graphs_trees/graph/graph.py","lineNumber":35,"sourceCode":"        self.adj_nodes = {}  # Key = key, val = Node\n        self.adj_weights = {}  # Key = key, val = weight\n\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]","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/donnemartin/interactive-coding-challenges/blob/358f2cc60426d5c4c3d7d580910eec9a7b393fa9/graphs_trees/graph/graph.py#L17-L53","documentation":"Raised by Node.remove_neighbor when the neighbor argument is None. Removing a None neighbor is meaningless because adjacency maps are keyed by neighbor.key, which would raise AttributeError otherwise. This is an explicit input validation guard on the low-level node API.","triggerScenarios":"Calling node.remove_neighbor(None) directly; passing a lookup result (e.g. graph.nodes.get(key)) that returned None.","commonSituations":"Using dict.get() to fetch a Node and passing the possibly-None result straight to remove_neighbor; confusing Graph-level key APIs with Node-level object APIs.","solutions":["Fetch nodes with graph.nodes[key] or check membership first so you never pass None","Use a Graph-level remove-edge helper if available instead of Node.remove_neighbor","Validate neighbor is a Node instance before calling"],"exampleFix":"# before\nnode.remove_neighbor(graph.nodes.get('x'))  # None if missing\n\n# after\nif 'x' in graph.nodes:\n    node.remove_neighbor(graph.nodes['x'])","handlingStrategy":"validation","validationCode":"if neighbor is not None:\n    node.remove_neighbor(neighbor)","typeGuard":"def is_node(obj) -> bool:\n    return obj is not None and hasattr(obj, 'key')","tryCatchPattern":"try:\n    node.remove_neighbor(neighbor)\nexcept TypeError:\n    pass  # nothing to remove","preventionTips":["Use graph.nodes[key] (not .get) so a missing node fails at lookup with a clear error","Check the value is a Node before calling node-level APIs"],"tags":["graph","adjacency-list","none-check","typeerror"],"backgroundTag":"none-argument-rejected","analyzedSha":"358f2cc60426d5c4c3d7d580910eec9a7b393fa9","analyzedAt":"2026-08-28T10:16:54.480Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}