JeffreySu/WeiXinMPSDK · error · UnRegisterAppIdException

此appId(…

Error message

此appId({0})尚未注册,请先使用AccessTokenContainer.Register完成注册(全局执行一次即可)!

What it means

GetAccessTokenResult throws UnRegisterAppIdException when CheckRegistered(appId) is false, meaning the appId was never registered in the AccessTokenContainer's cache. Senparc.Weixin requires a one-time AccessTokenContainer.Register(appId, appSecret) call (typically at application startup) before any token can be retrieved for that appId.

Solutions

  1. Call AccessTokenContainer.Register(appId, appSecret) once at application startup (e.g. in Startup/Program.cs) for every appId you will use.
  2. Verify the appId string exactly matches the one registered (case/whitespace).
  3. If you use Redis or another distributed cache, ensure the registration container shares the same cache domain as the consumer process.
  4. Log the registered appIds at startup and compare against the failing one to catch typos or missing tenants.

Example fix

// before
var token = AccessTokenContainer.GetAccessToken(appId); // throws UnRegisterAppIdException
// after
// at startup:
AccessTokenContainer.Register(appId, appSecret);
// then:
var token = AccessTokenContainer.GetAccessToken(appId);
Defensive patterns

Strategy: try-catch

Validate before calling

if (!AccessTokenContainer.CheckRegistered(appId))
{
    AccessTokenContainer.Register(appId, appSecret);
}

Type guard

bool IsTokenRegistered(string appId) => AccessTokenContainer.CheckRegistered(appId);

Try / catch

try
{
    var token = AccessTokenContainer.GetAccessToken(appId);
}
catch (UnRegisterAppIdException ex)
{
    _logger.LogError(ex, "appId {AppId} not registered in AccessTokenContainer; call Register at startup.", appId);
    AccessTokenContainer.Register(appId, _secrets.Get(appId));
    // retry once if appropriate
}

Prevention

When it happens

Trigger: Calling AccessTokenContainer.GetAccessToken(appId) or GetAccessTokenResult(appId) for an appId that was never registered via AccessTokenContainer.Register/RegisterAsync, or whose registration was lost because the cache was cleared/reset.

Common situations: Forgetting the startup Register call; registering in a process different from the one consuming the token (e.g. registering in a background worker, consuming in the web app); multi-tenant apps registering only the first tenant; cache restart (server reboot with memory cache) wiping registrations when using a non-persistent cache.

Related errors


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

Appendix: source

Thrown at src/Senparc.Weixin.MP/Senparc.Weixin.MP/Containers/AccessTokenContainer.cs:204

        /// <param name="appId"></param>
        /// <param name="getNewToken">是否强制重新获取新的Token</param>
        /// <returns></returns>
        public static string GetAccessToken(string appId, bool getNewToken = false)
        {
            return GetAccessTokenResult(appId, getNewToken).access_token;
        }

        /// <summary>
        /// 获取可用AccessTokenResult对象
        /// </summary>
        /// <param name="appId"></param>
        /// <param name="getNewToken">是否强制重新获取新的Token</param>
        /// <returns></returns>
        public static AccessTokenResult GetAccessTokenResult(string appId, bool getNewToken = false)
        {
            if (!CheckRegistered(appId))
            {
                throw new UnRegisterAppIdException(appId, string.Format("此appId({0})尚未注册,请先使用AccessTokenContainer.Register完成注册(全局执行一次即可)!", appId));
            }

            var accessTokenBag = TryGetItem(appId);

            using (Cache.BeginCacheLock(LockResourceName, appId))//同步锁
            {
                accessTokenBag = TryGetItem(appId);//获锁后重新读取,避免使用分布式缓存中的旧副本重复刷新
                if (getNewToken || accessTokenBag.AccessTokenExpireTime <= SystemTime.Now)
                {
                    //已过期,重新获取
                    accessTokenBag.AccessTokenResult = CommonApi.GetToken(accessTokenBag.AppId, accessTokenBag.AppSecret);
                    accessTokenBag.AccessTokenExpireTime = ApiUtility.GetExpireTime(accessTokenBag.AccessTokenResult.expires_in);
                    Update(accessTokenBag, null);//更新到缓存
                }
            }
            return accessTokenBag.AccessTokenResult;
        }

View on GitHub (pinned to be573f6f94)