{"record":{"id":"b67a8fd8f91c00c0","repo":"donnemartin/interactive-coding-challenges","slug":"items-or-total-weight-cannot-be-none","errorCode":null,"errorMessage":"items or total_weight cannot be None","messagePattern":"items or total_weight cannot be None","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"recursion_dynamic/knapsack_unbounded/knapsack_unbounded_solution.ipynb","lineNumber":184,"sourceCode":"  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"### Knapsack Bottom Up\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 2,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"class Knapsack(object):\\n\",\n    \"\\n\",\n    \"    def fill_knapsack(self, items, total_weight):\\n\",\n    \"        if items is None or total_weight is None:\\n\",\n    \"            raise TypeError('items or total_weight cannot be None')\\n\",\n    \"        if not items or total_weight == 0:\\n\",\n    \"            return 0\\n\",\n    \"        num_rows = len(items)\\n\",\n    \"        num_cols = total_weight + 1\\n\",\n    \"        T = [0] * (num_cols)\\n\",\n    \"        for i in range(num_rows):\\n\",\n    \"            for j in range(num_cols):\\n\",\n    \"                if j >= items[i].weight:\\n\",\n    \"                    T[j] = max(items[i].value + T[j - items[i].weight],\\n\",\n    \"                               T[j])\\n\",\n    \"        return T[-1]\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Unit Test\"","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/donnemartin/interactive-coding-challenges/blob/358f2cc60426d5c4c3d7d580910eec9a7b393fa9/recursion_dynamic/knapsack_unbounded/knapsack_unbounded_solution.ipynb#L166-L202","documentation":"Raised by the unbounded-knapsack Knapsack.fill_knapsack when items or total_weight is None. The method immediately computes num_rows = len(items) and num_cols = total_weight + 1, so None inputs are rejected up front with a TypeError instead of raising TypeError from len(None) or TypeError on None + 1.","triggerScenarios":"Calling fill_knapsack(None, 12) or fill_knapsack(items, None). Empty items or total_weight == 0 return 0 and are valid.","commonSituations":"Reusing the 0/1 knapsack call sites with the unbounded variant where loaders differ; items parsed from CSV rows that can be None; weight capacity sourced from an unset environment/config value.","solutions":["Pass a list of Item objects and an int capacity, both non-None","Default at the boundary: items = items or [], capacity = capacity or 0","Log and skip the computation when inputs are missing rather than propagating None"],"exampleFix":"// before\nval = Knapsack().fill_knapsack(items_from_csv, None)\n// after\ncapacity = int(os.getenv('CAPACITY', '0'))\nval = Knapsack().fill_knapsack(items_from_csv or [], capacity)","handlingStrategy":"validation","validationCode":"items = items or []\ntotal_weight = total_weight if total_weight is not None else 0\nKnapsack().fill_knapsack(items, total_weight)","typeGuard":"def valid_unbounded_args(items, w):\n    return isinstance(items, list) and isinstance(w, int) and w >= 0","tryCatchPattern":"try:\n    Knapsack().fill_knapsack(items, w)\nexcept TypeError as e:\n    raise HTTPException(400, str(e)) from e","preventionTips":["Default capacity from config with int()","Never let loaders return None"],"tags":["python","knapsack","unbounded","dynamic-programming","input-validation"],"backgroundTag":"none-argument-validation","analyzedSha":"358f2cc60426d5c4c3d7d580910eec9a7b393fa9","analyzedAt":"2026-08-28T10:16:54.480Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}