JeffreySu/WeiXinMPSDK · error · InvalidOperationException

当前已有 个注册委托,不能把容量降低到 。

Error message

当前已有 {RegisterFuncCollection.Count} 个注册委托,不能把容量降低到 {value}。

What it means

The MaximumRegistrationCallbackCount setter also prevents shrinking the capacity below the number of delegates already registered. If value < RegisterFuncCollection.Count, it throws InvalidOperationException rather than silently dropping existing registrations.

Solutions

  1. Unregister unused accounts/bags first (remove their registrations) until Count <= desired value, then set the new cap.
  2. Set the new value to at least RegisterFuncCollection.Count, or just leave the cap unchanged.
  3. Order initialization: set MaximumRegistrationCallbackCount before any registrations occur.
  4. Query the current count via reflection/registration APIs or simply set a larger value if shrink is unnecessary.

Example fix

// before
MyContainer.MaximumRegistrationCallbackCount = 10; // 50 already registered -> throws
// after
foreach (var stale in staleAppIds) MyContainer.Remove(stale); // unregister first
MyContainer.MaximumRegistrationCallbackCount = Math.Max(10, currentRegisteredCount);
Defensive patterns

Strategy: validation

Validate before calling

var desired = 10;
// currentCount can be tracked by your own registration bookkeeping
if (desired < currentRegisteredCount)
{
    // unregister stale bags first
    foreach (var key in staleKeys) MyContainer.Remove(key);
}
MyContainer.MaximumRegistrationCallbackCount = Math.Max(desired, currentRegisteredCount);

Try / catch

try
{
    MyContainer.MaximumRegistrationCallbackCount = newLimit;
}
catch (InvalidOperationException)
{
    Log("Too many existing registrations to shrink cap; skipping.");
}

Prevention

When it happens

Trigger: Lowering MaximumRegistrationCallbackCount on a container that already has more registered callbacks than the new value (e.g. many appIds/tokens registered, then setting the cap lower at runtime).

Common situations: Tightening limits in config after accounts have registered at startup; multi-tenant apps registering hundreds of appIds then a code path reducing the cap; race where registrations happen before the limit configuration runs.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of JeffreySu/WeiXinMPSDK@be573f6f94 (2026-09-12). Data as JSON: /api/errors/25836bc54cc89163. Report an issue: GitHub.

Appendix: source

Thrown at src/Senparc.Weixin/Senparc.Weixin/Containers/BaseContainer.cs:228

            get
            {
                lock (RegistrationCallbackSyncRoot)
                {
                    return _maximumRegistrationCallbackCount;
                }
            }
            set
            {
                if (value <= 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(value), "注册委托容量必须大于 0。");
                }

                lock (RegistrationCallbackSyncRoot)
                {
                    if (value < RegisterFuncCollection.Count)
                    {
                        throw new InvalidOperationException($"当前已有 {RegisterFuncCollection.Count} 个注册委托,不能把容量降低到 {value}。");
                    }

                    _maximumRegistrationCallbackCount = value;
                }
            }
        }

        /// <summary>
        /// 为 SDK 内部注册自动刷新委托,同时执行容量检查。
        /// 保留 <see cref="RegisterFuncCollection"/> 的历史类型,以兼容外部派生容器。
        /// </summary>
        protected static void SetRegistrationCallback(string shortKey, Func<Task<TBag>> registerFunc)
        {
            if (shortKey == null)
            {
                throw new ArgumentNullException(nameof(shortKey));
            }

View on GitHub (pinned to be573f6f94)