donnemartin/interactive-coding-challenges · error · KeyError
word does not exist
Error message
word does not exist
What it means
Trie.remove raises KeyError('word does not exist') when find(word) returns None, meaning no terminating path spells the word. This includes words never inserted, words already removed, and prefixes that exist as node paths but not as complete words (terminates is False).
Source
Thrown at graphs_trees/trie/trie_solution.ipynb:226
" def insert(self, word):\n",
" if word is None:\n",
" raise TypeError('word cannot be None')\n",
" node = self.root\n",
" parent = None\n",
" for char in word:\n",
" if char in node.children:\n",
" node = node.children[char]\n",
" else:\n",
" node.children[char] = Node(char, parent=node)\n",
" node = node.children[char]\n",
" node.terminates = True\n",
"\n",
" def remove(self, word):\n",
" if word is None:\n",
" raise TypeError('word cannot be None')\n",
" node = self.find(word)\n",
" if node is None:\n",
" raise KeyError('word does not exist')\n",
" node.terminates = False\n",
" parent = node.parent\n",
" while parent is not None:\n",
" # As we are propagating the delete up the \n",
" # parents, if this node has children, stop\n",
" # here to prevent orphaning its children.\n",
" # Or\n",
" # if this node is a terminating node that is\n",
" # not the terminating node of the input word, \n",
" # stop to prevent removing the associated word.\n",
" if node.children or node.terminates:\n",
" return\n",
" del parent.children[node.key]\n",
" node = parent\n",
" parent = parent.parent\n",
"\n",
" def list_words(self):\n",
" result = []\n",View on GitHub (pinned to 358f2cc604)
Solutions
- Check membership first: if trie.find(word) is not None: trie.remove(word), or note that find alone doesn't confirm termination — use a contains-style check
- Wrap remove in try/except KeyError for idempotent deletes
- Verify the word was actually inserted (and is a full word, not a prefix) before removal
Example fix
// before
trie.remove('foo') # KeyError if absent
// after
try:
trie.remove('foo')
except KeyError:
pass # already absent; deletion is idempotent Defensive patterns
Strategy: try-catch
Validate before calling
if trie.find(word) is not None:
trie.remove(word) Type guard
def is_stored_word(trie, word) -> bool:
node = trie.find(word)
return node is not None and node.terminates Try / catch
try:
trie.remove(word)
except KeyError:
pass # already absent; keep deletes idempotent Prevention
- Make delete flows idempotent by catching or pre-checking membership
- Remember prefixes of longer words are not themselves stored words
When it happens
Trigger: Calling trie.remove('foo') when 'foo' was never inserted; removing a word twice; removing a bare prefix like 'ab' when only 'abc' was inserted.
Common situations: Idempotent deletion code that assumes remove is safe to call repeatedly; deleting user-supplied words without checking membership; race where another thread already removed the word.
Related errors
AI-assisted analysis of donnemartin/interactive-coding-challenges@358f2cc604 (2026-08-28).
Data as JSON: /api/errors/0c6aab84d72cad52.
Report an issue: GitHub.