{"record":{"id":"6177d264e0287c5c","repo":"egametang/ET","slug":"invalid-capacity-capacity","errorCode":null,"errorMessage":"invalid capacity: {capacity}","messagePattern":"invalid capacity: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"Packages/cn.etetet.item/Scripts/Hotfix/Server/ItemComponentSystem.cs","lineNumber":150,"sourceCode":"                {\n                    item.Dispose();\n                }\n                self.SlotItems[i] = default;\n            }\n        }\n\n        #endregion\n\n        #region 业务辅助方法\n\n        /// <summary>\n        /// 设置背包容量\n        /// </summary>\n        public static void SetCapacity(this ItemComponent self, int capacity)\n        {\n            if (capacity < 0)\n            {\n                throw new Exception($\"invalid capacity: {capacity}\");\n            }\n\n            self.Capacity = capacity;\n            EnsureSlotContainerSize(self, capacity);\n        }\n\n        /// <summary>\n        /// 清空指定槽位\n        /// </summary>\n        public static void ClearSlot(this ItemComponent self, int slotIndex)\n        {\n            if ((uint)slotIndex >= (uint)self.SlotItems.Count)\n            {\n                return;\n            }\n\n            self.SlotItems[slotIndex] = default;\n        }","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/egametang/ET/blob/5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f/Packages/cn.etetet.item/Scripts/Hotfix/Server/ItemComponentSystem.cs#L132-L168","documentation":"Thrown by the SERVER-side ItemComponentSystem.SetCapacity when capacity < 0. SetCapacity writes self.Capacity and then grows the SlotItems container via EnsureSlotContainerSize. A negative capacity is meaningless for a slot list, so the guard rejects it hard. Note the CLIENT-side SetCapacity (Client/ItemComponentSystem.cs:76) does NOT throw — it logs and returns — so this throw is server-authoritative only.","triggerScenarios":"Calling the server extension ItemComponentSystem.SetCapacity(this ItemComponent, int) (line 146) with a negative int. Reached from ItemHelper.SetCapacity (line 14) which forwards directly, or from any server code that computes capacity from player level/config and underflows.","commonSituations":"A config-driven capacity table returns -1 as a 'not found' sentinel and is passed straight in; an arithmetic underflow (e.g. baseCapacity - penalty where penalty > baseCapacity); a deserialized capacity field corrupted to a negative value.","solutions":["Clamp the computed capacity to >= 0 before calling SetCapacity (e.g. Math.Max(0, computed)).","Fix the config sentinel: make 'not found' return 0 or a real default, never -1.","Add a precondition at the caller (ItemHelper.SetCapacity) so the raw server API never sees a negative value."],"exampleFix":"// before\nint cap = configTable.Get(player.Level); // returns -1 when missing\ncomponent.SetCapacity(cap);\n\n// after\nint cap = configTable.Get(player.Level);\nif (cap < 0) cap = 0; // explicit default\ncomponent.SetCapacity(cap);","handlingStrategy":"validation","validationCode":"int safeCap = capacity < 0 ? 0 : capacity;\ncomponent.SetCapacity(safeCap);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never use -1 as a 'not found' sentinel for capacity; use 0 or a nullable.","Clamp config-driven capacity to >= 0 at the data source.","Unit-test SetCapacity with boundary values (0, negative, large)."],"tags":["item","server","capacity","validation","config"],"backgroundTag":null,"analyzedSha":"5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f","analyzedAt":"2026-08-13T21:10:40.377Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}