{"record":{"id":"60e2fc7d6f539193","repo":"egametang/ET","slug":"slot-index-slotindex-exceeds-capacity-self-capa","errorCode":null,"errorMessage":"slot index {slotIndex} exceeds capacity {self.Capacity}","messagePattern":"slot index (.+?) exceeds capacity (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"Packages/cn.etetet.item/Scripts/Hotfix/Client/ItemComponentSystem.cs","lineNumber":204,"sourceCode":"            }\n\n            self.SlotItems[slotIndex] = default;\n        }\n\n        #endregion\n\n        #region 私有方法\n\n        private static void EnsureSlotIndex(ItemComponent self, int slotIndex)\n        {\n            if (slotIndex < 0)\n            {\n                throw new Exception($\"invalid slot index: {slotIndex}\");\n            }\n\n            if (slotIndex >= self.Capacity)\n            {\n                throw new Exception($\"slot index {slotIndex} exceeds capacity {self.Capacity}\");\n            }\n        }\n\n        private static void EnsureSlotContainerSize(ItemComponent self, int size)\n        {\n            if (size <= 0)\n            {\n                return;\n            }\n\n            if (self.SlotItems.Count >= size)\n            {\n                return;\n            }\n\n            int addCount = size - self.SlotItems.Count;\n            for (int i = 0; i < addCount; ++i)\n            {","sourceCodeStart":186,"sourceCodeEnd":222,"githubUrl":"https://github.com/egametang/ET/blob/5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f/Packages/cn.etetet.item/Scripts/Hotfix/Client/ItemComponentSystem.cs#L186-L222","documentation":"Thrown by the CLIENT-side ItemComponentSystem.EnsureSlotIndex when a slot index is >= the bag's Capacity. EnsureSlotIndex guards UpdateItem and SetSlotItem on the client. The client bag defaults to capacity 100 (Awake), so any server-pushed slotIndex at or above that ceiling trips this guard. It is a hard invariants check, not a recoverable runtime state — the client expects the server to only ever reference slots that already exist locally.","triggerScenarios":"A server-to-client M2C_UpdateItem message carries a SlotIndex >= self.Capacity, and Client ItemComponentSystem.UpdateItem (line 35) calls EnsureSlotIndex before placing the item. Also reached via Client SetSlotItem (line 169). Happens when the server expanded capacity (SetCapacity) and pushed items into new slots before the M2C_UpdateBagCapacity message was applied client-side, or when client Capacity was never grown to match.","commonSituations":"Server/client capacity desync after server grows the bag; ordering bug where item updates arrive before the capacity-update message; a serialized Capacity that differs between server and client rebuilds; a custom caller passing a literal slot index without checking Capacity first.","solutions":["Ensure the server sends and the client applies M2C_UpdateBagCapacity (which calls Client SetCapacity) BEFORE any M2C_UpdateItem referencing the new slots.","Check self.Capacity client-side before calling UpdateItem/SetSlotItem and, if the index is out of range, force a full bag sync from the server.","Verify the serialized Capacity value is identical on server and client after a hot-reload or rebuild.","Stop passing hand-computed slot indices; always obtain them from FindEmptySlot / server-authoritative data."],"exampleFix":"// before — server grows bag then immediately pushes item at new slot\nItemHelper.SetCapacity(component, 120);\nNotifyItemUpdate(component, itemAtSlot115);\n\n// after — capacity message is flushed/ordered before item updates\nItemHelper.SetCapacity(component, 120); // sends M2C_UpdateBagCapacity\n// ensure client applies capacity change (flush/ordered send) before item updates\nNotifyItemUpdate(component, itemAtSlot115);","handlingStrategy":"validation","validationCode":"// Client: before applying a server item update, ensure the slot exists locally.\npublic static void SafeUpdateItem(this ItemComponent self, long itemId, int slotIndex, int configId, int count)\n{\n    if (slotIndex < 0 || slotIndex >= self.Capacity)\n    {\n        Log.Error($\"reject item update: slot {slotIndex} out of range (cap {self.Capacity}); requesting full sync\");\n        // trigger a server re-sync of the bag here\n        return;\n    }\n    self.UpdateItem(itemId, slotIndex, configId, count);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always send M2C_UpdateBagCapacity before any item update that targets a new slot.","Never cache Capacity; read self.Capacity at the point of use.","After a hot-reload/rebuild, force a full bag resync to reconcile server/client capacity."],"tags":["item","client","slot-index","capacity","state-desync"],"backgroundTag":null,"analyzedSha":"5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f","analyzedAt":"2026-08-13T21:10:40.377Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}