{"record":{"id":"4462a4d0d3a401d6","repo":"donnemartin/interactive-coding-challenges","slug":"end-indices-must-be-0","errorCode":null,"errorMessage":"end indices must be >= 0","messagePattern":"end indices must be >= 0","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sorting_searching/merge_into/merge_into_solution.ipynb","lineNumber":161,"sourceCode":"   \"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 Array(object):\\n\",\n    \"\\n\",\n    \"    def merge_into(self, source, dest, source_end_index, dest_end_index):\\n\",\n    \"        if source is None or dest is None:\\n\",\n    \"            raise TypeError('source or dest cannot be None')\\n\",\n    \"        if source_end_index < 0 or dest_end_index < 0:\\n\",\n    \"            raise ValueError('end indices must be >= 0')\\n\",\n    \"        if not source:\\n\",\n    \"            return dest\\n\",\n    \"        if not dest:\\n\",\n    \"            return source\\n\",\n    \"        source_index = source_end_index - 1\\n\",\n    \"        dest_index = dest_end_index - 1\\n\",\n    \"        insert_index = source_end_index + dest_end_index - 1\\n\",\n    \"        while dest_index >= 0:\\n\",\n    \"            if source[source_index] > dest[dest_index]:\\n\",\n    \"                source[insert_index] = source[source_index]\\n\",\n    \"                source_index -= 1\\n\",\n    \"            else:\\n\",\n    \"                source[insert_index] = dest[dest_index]\\n\",\n    \"                dest_index -= 1\\n\",\n    \"            insert_index -= 1\\n\",\n    \"        return source\"\n   ]\n  },","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/donnemartin/interactive-coding-challenges/blob/358f2cc60426d5c4c3d7d580910eec9a7b393fa9/sorting_searching/merge_into/merge_into_solution.ipynb#L143-L179","documentation":"Raised by Array.merge_into when source_end_index or dest_end_index is negative. It is a ValueError thrown after the None check on the arrays, because the method converts them to zero-based indices via index - 1 and walks backwards; a negative end index would produce invalid slicing behavior.","triggerScenarios":"Calling merge_into(source, dest, -1, 5) or any call where either end index is < 0. Commonly happens when an end index is computed as len(empty_list) - 1 = -1.","commonSituations":"Passing len(x) - 1 where x is empty; off-by-one arithmetic on sizes; indices derived from user-supplied lengths that were not validated as non-negative.","solutions":["Compute end indices as len(list), not len(list) - 1 (the method subtracts 1 internally)","Skip merging when either list is empty instead of computing -1","Validate indices >= 0 at the call site before invoking"],"exampleFix":"// before\narr.merge_into(src, dest, len(src) - 1, len(dest))\n// after\narr.merge_into(src, dest, len(src), len(dest))","handlingStrategy":"validation","validationCode":"if source_end_index < 0 or dest_end_index < 0:\n    return dest\narr.merge_into(source, dest, source_end_index, dest_end_index)","typeGuard":"def valid_indices(i, j):\n    return isinstance(i, int) and isinstance(j, int) and i >= 0 and j >= 0","tryCatchPattern":"try:\n    arr.merge_into(src, dest, i, j)\nexcept ValueError as e:\n    if 'end indices' in str(e):\n        # recompute with len() instead of len()-1\n        ...","preventionTips":["Pass len(list) as end index (method subtracts 1 internally)","Skip empty-list merges"],"tags":["python","merge","array","valueerror","index-validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"358f2cc60426d5c4c3d7d580910eec9a7b393fa9","analyzedAt":"2026-08-28T10:16:54.480Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}