{"record":{"id":"a66272f1c566a40b","repo":"donnemartin/interactive-coding-challenges","slug":"word-does-not-exist","errorCode":null,"errorMessage":"word does not exist","messagePattern":"word does not exist","errorType":"validation","errorClass":"KeyError","httpStatus":null,"severity":"error","filePath":"graphs_trees/trie/trie.py","lineNumber":47,"sourceCode":"    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 = []","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/donnemartin/interactive-coding-challenges/blob/358f2cc60426d5c4c3d7d580910eec9a7b393fa9/graphs_trees/trie/trie.py#L29-L65","documentation":"Raised by Trie.remove when the word is not stored as a terminated word in the trie. find returns a node only if the full path exists AND the final node has terminates=True; otherwise remove raises KeyError. Prefixes of stored words also trigger this (e.g. removing 'ab' when only 'abc' is stored).","triggerScenarios":"Calling remove on a never-inserted word; removing a word twice; removing a proper prefix of a stored word.","commonSituations":"Duplicate delete requests in request handling; deleting from stale word lists; assuming prefixes count as words.","solutions":["Check with trie.find(word) first and only remove if it returns a node","Track deletion state upstream to avoid double-remove","Catch KeyError and treat 'already absent' as success (idempotent delete)"],"exampleFix":"# before\ntrie.remove(word)  # KeyError if absent\n\n# after\nif trie.find(word) is not None:\n    trie.remove(word)","handlingStrategy":"try-catch","validationCode":"if trie.find(word) is not None:\n    trie.remove(word)","typeGuard":"def word_in_trie(trie, word) -> bool:\n    return word is not None and trie.find(word) is not None","tryCatchPattern":"try:\n    trie.remove(word)\nexcept KeyError:\n    pass  # word already absent","preventionTips":["Check with find() before remove","Make delete handlers idempotent by catching KeyError"],"tags":["trie","remove","keyerror","word-not-found"],"backgroundTag":"key-not-in-collection","analyzedSha":"358f2cc60426d5c4c3d7d580910eec9a7b393fa9","analyzedAt":"2026-08-28T10:16:54.480Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}