donnemartin/interactive-coding-challenges · error · KeyError

Invalid key

Error message

Invalid key

What it means

Raised by Graph.add_edge(source_key, dest_key, weight) when source_key or dest_key is None. The method auto-creates missing nodes, but None is not an acceptable key, so it raises KeyError('Invalid key') rather than silently creating a None-keyed node. Note this fires before the None keys can flow into add_node.

Source

Thrown at graphs_trees/graph/graph_solution.ipynb:225

    "        del self.adj_weights[neighbor.key]\n",
    "        del self.adj_nodes[neighbor.key]\n",
    "\n",
    "\n",
    "class 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):\n",
    "        if source_key is None or dest_key is None:\n",
    "            raise KeyError('Invalid key')\n",
    "        if source_key not in self.nodes:\n",
    "            self.add_node(source_key)\n",
    "        if dest_key not in self.nodes:\n",
    "            self.add_node(dest_key)\n",
    "        self.nodes[source_key].add_neighbor(self.nodes[dest_key], weight)\n",
    "\n",
    "    def add_undirected_edge(self, src_key, dst_key, weight=0):\n",
    "        if src_key is None or dst_key is None:\n",
    "            raise TypeError('key cannot be None')\n",
    "        self.add_edge(src_key, dst_key, weight)\n",
    "        self.add_edge(dst_key, src_key, weight)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],

View on GitHub (pinned to 358f2cc604)

Solutions

  1. Validate both endpoint keys are non-None before calling add_edge
  2. Fix upstream data: fill or drop edges with null endpoints at load time
  3. If None means 'not found', use graph.nodes.get() and skip edge creation when it returns None

Example fix

# before
graph.add_edge(row['src'], row['dst'])  # KeyError when a column is null

# after
if row['src'] is not None and row['dst'] is not None:
    graph.add_edge(row['src'], row['dst'])
Defensive patterns

Strategy: validation

Validate before calling

if source_key is not None and dest_key is not None:
    graph.add_edge(source_key, dest_key, weight)

Type guard

def is_valid_edge(src, dst):
    return src is not None and dst is not None

Try / catch

try:
    graph.add_edge(src, dst, weight)
except KeyError as e:
    if 'Invalid key' in str(e):
        log_bad_edge(src, dst)
    else:
        raise

Prevention

When it happens

Trigger: Calling add_edge(None, 'b'), add_edge('a', None), or add_edge(x, y) where x/y came from a failed lookup like graph.nodes.get(missing) or a nullable data field.

Common situations: Building graphs from edge lists with null endpoint columns; passing variables that were never initialized because an earlier step failed silently; confusing None with the default weight parameter positionally (add_edge('a', None)).

Related errors


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