{"record":{"id":"2ab44c8dae757b4b","repo":"DrKLO/Telegram","slug":"index-out-of-bounds-passed-position-old-li","errorCode":null,"errorMessage":"Index out of bounds - passed position = {}, old list size = {}","messagePattern":"Index out of bounds - passed position = (.+?), old list size = (.+?)","errorType":"exception","errorClass":"IndexOutOfBoundsException","httpStatus":null,"severity":"error","filePath":"TMessagesProj/src/main/java/androidx/recyclerview/widget/DiffUtil.java","lineNumber":672,"sourceCode":"                return; // already set by a latter item\n            }\n            findMatchingItem(x, y, snakeIndex, true);\n        }\n\n        /**\n         * Given a position in the old list, returns the position in the new list, or\n         * {@code NO_POSITION} if it was removed.\n         *\n         * @param oldListPosition Position of item in old list\n         *\n         * @return Position of item in new list, or {@code NO_POSITION} if not present.\n         *\n         * @see #NO_POSITION\n         * @see #convertNewPositionToOld(int)\n         */\n        public int convertOldPositionToNew(@IntRange(from = 0) int oldListPosition) {\n            if (oldListPosition < 0 || oldListPosition >= mOldListSize) {\n                throw new IndexOutOfBoundsException(\"Index out of bounds - passed position = \"\n                        + oldListPosition + \", old list size = \" + mOldListSize);\n            }\n            final int status = mOldItemStatuses[oldListPosition];\n            if ((status & FLAG_MASK) == 0) {\n                return NO_POSITION;\n            } else {\n                return status >> FLAG_OFFSET;\n            }\n        }\n\n        /**\n         * Given a position in the new list, returns the position in the old list, or\n         * {@code NO_POSITION} if it was removed.\n         *\n         * @param newListPosition Position of item in new list\n         *\n         * @return Position of item in old list, or {@code NO_POSITION} if not present.\n         *","sourceCodeStart":654,"sourceCodeEnd":690,"githubUrl":"https://github.com/DrKLO/Telegram/blob/45ab8f4308496e1f01026a97fcdb0d58a5274474/TMessagesProj/src/main/java/androidx/recyclerview/widget/DiffUtil.java#L654-L690","documentation":"After DiffUtil computes a result, convertOldPositionToNew maps a position in the OLD list to its new position (or NO_POSITION if removed). It reads mOldItemStatuses[oldListPosition], which was sized to mOldListSize at result construction. Passing oldListPosition >= mOldListSize or < 0 would read out of bounds, so DiffUtil guards explicitly. The exception means the caller is feeding a position that exceeds the old list size that the DiffResult was computed against — typically because the list changed between computing the diff and querying the result.","triggerScenarios":"Computing a DiffResult against list A of size N, then querying convertOldPositionToNew with position >= N after the list grew; off-by-one in a loop using the new list size instead of the old; caching a DiffResult and reusing it after the source list mutated.","commonSituations":"Saving DiffResult across adapter.setList calls; chat app appending messages and then re-querying an old DiffResult; confusing old vs new position semantics when building move callbacks.","solutions":["Only call convertOldPositionToNew with positions in [0, diffResult-specific oldListSize).","Recompute the DiffResult whenever the source list changes; do not cache across mutations.","Track the old list size at diff time and clamp/bounds-check before converting."],"exampleFix":"// before\nint newPos = result.convertOldPositionToNew(pos); // pos may exceed old size\n\n// after\nint oldSize = oldList.size();\nint newPos = (pos >= 0 && pos < oldSize)\n    ? result.convertOldPositionToNew(pos)\n    : DiffUtil.DiffResult.NO_POSITION;","handlingStrategy":"validation","validationCode":"// Bounds-check against the old list size captured at diff time\nint oldSize = oldSnap.size();\nint safeConvertNew(DiffUtil.DiffResult r, int oldPos) {\n    if (oldPos < 0 || oldPos >= oldSize) return DiffUtil.DiffResult.NO_POSITION;\n    return r.convertOldPositionToNew(oldPos);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Recompute the DiffResult whenever the source list changes.","Keep a reference to the old-list size at diff time for bounds checks.","Never reuse a DiffResult after the backing list mutates."],"tags":["recyclerview","diffutil","bounds","position-mapping"],"backgroundTag":null,"analyzedSha":"45ab8f4308496e1f01026a97fcdb0d58a5274474","analyzedAt":"2026-08-14T05:19:30.815Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}