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
- Call AccessTokenContainer.Register(appId, appSecret) once at application startup (e.g. in Startup/Program.cs) for every appId you will use.
- Verify the appId string exactly matches the one registered (case/whitespace).
- If you use Redis or another distributed cache, ensure the registration container shares the same cache domain as the consumer process.
- 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
- Register every appId in a single, centralized startup routine (Program.cs/Startup.cs).
- Keep registration and consumption in the same process and cache domain.
- Use a distributed cache (Redis) so registrations survive restarts and multi-instance deployments.
- Add a health check that verifies CheckRegistered(appId) for all configured appIds.
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
- AppId 不能为空。
- AppId 不能为空。
- 此appId尚未注册,请先使用JsApiTicketContainer.Register完成注册(全局执行一次即可)!
- 此 appId code 尚未注册,请先使用 OAuthAccessTokenContainer.Register…
- 注册委托容量必须大于 0。
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)