JeffreySu/WeiXinMPSDK · error · WeixinWorkException

UN_REGISTER_ALERT

Error message

UN_REGISTER_ALERT

What it means

ProviderTokenContainer.GetTokenResult throws WeixinWorkException with UN_REGISTER_ALERT ("此CorpId尚未注册,ProviderTokenContainer.Register完成注册(全局执行一次即可)!") when CheckRegistered(AccessTokenContainer.BuildingKey(corpId, corpSecret)) is false. Provider (通讯录/服务商) tokens require a prior ProviderTokenContainer.Register call that stores the token bag in cache. GetToken delegates to this method, so callers see the same exception.

Solutions

  1. Call ProviderTokenContainer.Register(corpId, corpSecret) once at application startup before any GetToken call.
  2. Ensure the corpId/corpSecret pair used in GetToken is identical to the one registered.
  3. Re-run registration after cache restarts; prefer registering in app startup code, not one-off scripts.
  4. Wrap first access in a CheckRegistered check that registers on demand for multi-tenant apps.

Example fix

// before
var token = ProviderTokenContainer.GetToken(corpId, corpSecret); // throws: not registered
// after
if (!ProviderTokenContainer.CheckRegistered(corpId, corpSecret))
{
    ProviderTokenContainer.Register(corpId, corpSecret);
}
var token = ProviderTokenContainer.GetToken(corpId, corpSecret);
Defensive patterns

Strategy: validation

Validate before calling

if (!ProviderTokenContainer.CheckRegistered(corpId, corpSecret))
{
    ProviderTokenContainer.Register(corpId, corpSecret);
}

Try / catch

try
{
    var token = ProviderTokenContainer.GetToken(corpId, corpSecret);
}
catch (WeixinWorkException ex) when (ex.Message.Contains("尚未注册"))
{
    log.LogError(ex, "Provider token for {CorpId} not registered; registering at first use.", corpId);
    ProviderTokenContainer.Register(corpId, corpSecret);
}

Prevention

When it happens

Trigger: Calling ProviderTokenContainer.GetToken/GetTokenResult(corpId, corpSecret) without a prior Register(corpId, corpSecret); corpSecret changed so the built key no longer matches the registered one; cache provider emptied.

Common situations: New environment deployment where startup registration was omitted; rotating corpSecret invalidates the cache key; in-memory cache reset on app pool recycle with registration only in a one-time script.

Related errors


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

Appendix: source

Thrown at src/Senparc.Weixin.Work/Senparc.Weixin.Work/Containers/ProviderTokenContainer.cs:192

        /// <param name="getNewToken">是否强制重新获取新的Token</param>
        /// <returns></returns>
        public static string GetToken(string corpId, string corpSecret, bool getNewToken = false)
        {
            return GetTokenResult(corpId, corpSecret, getNewToken).provider_access_token;
        }

        /// <summary>
        /// 获取可用Token
        /// </summary>
        /// <param name="corpId"></param>
        /// <param name="corpSecret"></param>
        /// <param name="getNewToken">是否强制重新获取新的Token</param>
        /// <returns></returns>
        public static ProviderTokenResult GetTokenResult(string corpId, string corpSecret, bool getNewToken = false)
        {
            if (!CheckRegistered(AccessTokenContainer.BuildingKey(corpId, corpSecret)))
            {
                throw new WeixinWorkException(UN_REGISTER_ALERT);
            }

            var shortKey = AccessTokenContainer.BuildingKey(corpId, corpSecret);
            var providerTokenBag = TryGetItem(shortKey);
            using (Cache.BeginCacheLock(LockResourceName, shortKey))
            {
                providerTokenBag = TryGetItem(shortKey);//获锁后重新读取并二次检查过期状态
                if (getNewToken || providerTokenBag.ExpireTime <= SystemTime.Now)
                {
                    //已过期,重新获取
                    providerTokenBag.ProviderTokenResult = SsoApi.GetProviderToken(providerTokenBag.CorpId, providerTokenBag.CorpSecret);
                    providerTokenBag.ExpireTime = ApiUtility.GetExpireTime(providerTokenBag.ProviderTokenResult.expires_in);
                    Update(providerTokenBag, null);//更新到缓存
                }
            }
            return providerTokenBag.ProviderTokenResult;
        }

View on GitHub (pinned to be573f6f94)