{"record":{"id":"6f7875e34bc0c719","repo":"abpframework/abp","slug":"targetindex-should-be-between-0-and-source-count","errorCode":null,"errorMessage":"targetIndex should be between 0 and {source.Count - 1}","messagePattern":"targetIndex should be between 0 and (.+?)","errorType":"exception","errorClass":"IndexOutOfRangeException","httpStatus":null,"severity":"error","filePath":"framework/src/Volo.Abp.Core/System/Collections/Generic/AbpListExtensions.cs","lineNumber":155,"sourceCode":"    }\n\n    public static void ReplaceOne<T>(this IList<T> source, T item, T replaceWith)\n    {\n        for (int i = 0; i < source.Count; i++)\n        {\n            if (Comparer<T>.Default.Compare(source[i], item) == 0)\n            {\n                source[i] = replaceWith;\n                return;\n            }\n        }\n    }\n\n    public static void MoveItem<T>(this List<T> source, Predicate<T> selector, int targetIndex)\n    {\n        if (!targetIndex.IsBetween(0, source.Count - 1))\n        {\n            throw new IndexOutOfRangeException(\"targetIndex should be between 0 and \" + (source.Count - 1));\n        }\n\n        var currentIndex = source.FindIndex(0, selector);\n        if (currentIndex == targetIndex)\n        {\n            return;\n        }\n\n        var item = source[currentIndex];\n        source.RemoveAt(currentIndex);\n        source.Insert(targetIndex, item);\n    }\n\n    [NotNull]\n    public static T GetOrAdd<T>([NotNull] this IList<T> source, Func<T, bool> selector, Func<T> factory)\n    {\n        Check.NotNull(source, nameof(source));\n","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/abpframework/abp/blob/7ed43b1931b9df46a50c0c59148a18645641d0df/framework/src/Volo.Abp.Core/System/Collections/Generic/AbpListExtensions.cs#L137-L173","documentation":"Thrown by AbpListExtensions.MoveItem when targetIndex is outside [0, source.Count - 1]. MoveItem relocates the element matching selector to targetIndex via RemoveAt + Insert, so an out-of-range index is rejected up front with IndexOutOfRangeException. An empty list makes the valid range [0, -1], so any targetIndex throws.","triggerScenarios":"Calling list.MoveItem(selector, targetIndex) with targetIndex < 0 or >= list.Count; calling on an empty list; computing targetIndex from a stale count.","commonSituations":"UI reorder logic that passes an index from a different-sized list; off-by-one (using Count instead of Count-1); calling MoveItem before the list is populated.","solutions":["Bound-check targetIndex before calling: targetIndex = Math.Clamp(targetIndex, 0, source.Count - 1) (only if Count > 0).","Ensure the list is non-empty and targetIndex was computed from the current Count.","Handle the empty-list case explicitly before attempting to move an item."],"exampleFix":"// before\nlist.MoveItem(x => x.Id == id, newIndex); // throws if newIndex out of range\n\n// after\nif (list.Count == 0) return;\nlist.MoveItem(x => x.Id == id, Math.Clamp(newIndex, 0, list.Count - 1));","handlingStrategy":"validation","validationCode":"// Bound-check before moving, and handle empty lists\nif (source.Count > 0)\n    source.MoveItem(selector, Math.Clamp(targetIndex, 0, source.Count - 1));","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Compute targetIndex from the live list Count, not a stale value.","Guard the empty-list case before calling MoveItem.","Use Math.Clamp to keep targetIndex in [0, Count-1]."],"tags":["collections","extension-method","argument","abp-core"],"backgroundTag":null,"analyzedSha":"7ed43b1931b9df46a50c0c59148a18645641d0df","analyzedAt":"2026-08-13T16:26:11.351Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}