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
- Call ProviderTokenContainer.Register(corpId, corpSecret) once at application startup before any GetToken call.
- Ensure the corpId/corpSecret pair used in GetToken is identical to the one registered.
- Re-run registration after cache restarts; prefer registering in app startup code, not one-off scripts.
- 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
- Register provider credentials in application startup, not in manual/one-time setup steps.
- After rotating corpSecret, re-register so the cache key matches.
- Monitor the WeixinTrace logs for UN_REGISTER_ALERT to catch missed registrations early.
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)