{"record":{"id":"2da4c3f85f4bfa3d","repo":"donnemartin/interactive-coding-challenges","slug":"ransom-note-or-magazine-cannot-be-none","errorCode":null,"errorMessage":"ransom_note or magazine cannot be None","messagePattern":"ransom_note or magazine cannot be None","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"online_judges/ransom_note/ransom_note_solution.ipynb","lineNumber":93,"sourceCode":"  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Code\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 1,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"class Solution(object):\\n\",\n    \"\\n\",\n    \"    def match_note_to_magazine(self, ransom_note, magazine):\\n\",\n    \"        if ransom_note is None or magazine is None:\\n\",\n    \"            raise TypeError('ransom_note or magazine cannot be None')\\n\",\n    \"        seen_chars = {}\\n\",\n    \"        for char in magazine:\\n\",\n    \"            if char in seen_chars:\\n\",\n    \"                seen_chars[char] += 1\\n\",\n    \"            else:\\n\",\n    \"                seen_chars[char] = 1\\n\",\n    \"        for char in ransom_note:\\n\",\n    \"            try:\\n\",\n    \"                seen_chars[char] -= 1\\n\",\n    \"            except KeyError:\\n\",\n    \"                return False\\n\",\n    \"            if seen_chars[char] < 0:\\n\",\n    \"                return False\\n\",\n    \"        return True\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/donnemartin/interactive-coding-challenges/blob/358f2cc60426d5c4c3d7d580910eec9a7b393fa9/online_judges/ransom_note/ransom_note_solution.ipynb#L75-L111","documentation":"Raised by Solution.match_note_to_magazine when either ransom_note or magazine is None. The method builds a character-count dict from the magazine and then consumes it against the note, so both must be actual strings; the combined guard rejects None for either argument with a clear message.","triggerScenarios":"Calling match_note_to_magazine(None, 'abc'), match_note_to_magazine('abc', None), or with both None.","commonSituations":"Text-extraction steps (OCR, file read, HTTP fetch) that return None on failure and are passed straight in; optional fields from a form or API payload.","solutions":["Default both arguments to '' at the call site: match_note_to_magazine(note or '', mag or '').","Fix the extraction step to raise or return '' instead of None.","Wrap the call in try/except TypeError for robust batch processing."],"exampleFix":"# before\nSolution().match_note_to_magazine(note, mag)  # note may be None\n\n# after\nSolution().match_note_to_magazine(note or '', mag or '')","handlingStrategy":"type-guard","validationCode":"note = note or ''\nmagazine = magazine or ''\ncan_match = Solution().match_note_to_magazine(note, magazine)","typeGuard":"def is_str(x):\n    return isinstance(x, str)","tryCatchPattern":"try:\n    Solution().match_note_to_magazine(note, magazine)\nexcept TypeError as e:\n    if 'cannot be None' in str(e):\n        can_match = False\n    else:\n        raise","preventionTips":["Make text extraction return '' on failure instead of None.","Coalesce both string arguments with 'or \"\"' before calling."],"tags":["python","null-check","string","typeerror"],"backgroundTag":"none-argument-guard","analyzedSha":"358f2cc60426d5c4c3d7d580910eec9a7b393fa9","analyzedAt":"2026-08-28T10:16:54.480Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}