donnemartin/interactive-coding-challenges · error · TypeError

neighbor cannot be None

Error message

neighbor cannot be None

What it means

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.

Source

Thrown at graphs_trees/graph/graph.py:35

        self.adj_nodes = {}  # Key = key, val = Node
        self.adj_weights = {}  # Key = key, val = weight

    def __repr__(self):
        return str(self.key)

    def __lt__(self, other):
        return self.key < other.key

    def add_neighbor(self, neighbor, weight=0):
        if neighbor is None or weight is None:
            raise TypeError('neighbor or weight cannot be None')
        neighbor.incoming_edges += 1
        self.adj_weights[neighbor.key] = weight
        self.adj_nodes[neighbor.key] = neighbor

    def remove_neighbor(self, neighbor):
        if neighbor is None:
            raise TypeError('neighbor cannot be None')
        if neighbor.key not in self.adj_nodes:
            raise KeyError('neighbor not found')
        neighbor.incoming_edges -= 1
        del self.adj_weights[neighbor.key]
        del self.adj_nodes[neighbor.key]


class Graph:

    def __init__(self):
        self.nodes = {}  # Key = key, val = Node

    def add_node(self, key):
        if key is None:
            raise TypeError('key cannot be None')
        if key not in self.nodes:
            self.nodes[key] = Node(key)
        return self.nodes[key]

View on GitHub (pinned to 358f2cc604)

Solutions

  1. Fetch nodes with graph.nodes[key] or check membership first so you never pass None
  2. Use a Graph-level remove-edge helper if available instead of Node.remove_neighbor
  3. Validate neighbor is a Node instance before calling

Example fix

# before
node.remove_neighbor(graph.nodes.get('x'))  # None if missing

# after
if 'x' in graph.nodes:
    node.remove_neighbor(graph.nodes['x'])
Defensive patterns

Strategy: validation

Validate before calling

if neighbor is not None:
    node.remove_neighbor(neighbor)

Type guard

def is_node(obj) -> bool:
    return obj is not None and hasattr(obj, 'key')

Try / catch

try:
    node.remove_neighbor(neighbor)
except TypeError:
    pass  # nothing to remove

Prevention

When it happens

Trigger: Calling node.remove_neighbor(None) directly; passing a lookup result (e.g. graph.nodes.get(key)) that returned None.

Common situations: 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.

Related errors


AI-assisted analysis of donnemartin/interactive-coding-challenges@358f2cc604 (2026-08-28). Data as JSON: /api/errors/9df9516ce4264359. Report an issue: GitHub.